【问题标题】:Replace nodes of one xml document selected from another document using XPath - Saxon .net API使用 XPath - Saxon .net API 替换从另一个文档中选择的一个 xml 文档的节点
【发布时间】:2015-07-06 11:03:52
【问题描述】:

我正在尝试用使用相同 XPath 从另一个文档中选择的节点替换一个文档中的节点。我正在使用 Saxon XPath 选择器从两个文档中选择节点,但我没有找到任何关于如何替换节点的线索。

假设我的 XPath 是:/bookstore/book,以下是我迄今为止编写的一段代码,用于从源文档和目标文档访问节点。

Processor SaxonProcessor = new Processor();
XPathCompiler Compiler = SaxonProcessor.NewXPathCompiler();

XmlDocument xmlDocumentTarget = new XmlDocument();
xmlDocumentTarget.LoadXml(targetXml);

DocumentBuilder sBuilder = SaxonProcessor.NewDocumentBuilder();
var sourceNode = sBuilder.Wrap(xmlDocumentSource);

XmlDocument xmlDocumentTarget = new XmlDocument();
xmlDocumentTarget.LoadXml(targetXml);

DocumentBuilder sBuilder = SaxonProcessor.NewDocumentBuilder();
var sourceDoc = sBuilder.Wrap(xmlDocumentSource);

DocumentBuilder tBuilder = SaxonProcessor.NewDocumentBuilder();
var targetDoc = tBuilder.Wrap(xmlDocumentTarget);

string xPath = @"/bookstore/book";
var sourceExp = Compiler.Compile(xPath).Load();
sourceExp.ContextItem = sourceDoc;

var targetExp = Compiler.Compile(xPath).Load();
targetExp.ContextItem = targetDoc;

var sourceXdmValue = sourceExp.Evaluate(); // Gives me source nodes
var targetXdmValue = targetExp.Evaluate(); // Gives me target nodes to replace

现在我想用源文档中的节点替换目标文档中的节点。如何使用 Saxon API 做到这一点?

请注意,在目标文档中,不包括具有“my”命名空间的书,因为不会根据提供的 XPath 从源中选择该书。

源 XML

<bookstore specialty="novel">
  <book style="autobiography">
    <author>
      <first-name>Joe</first-name>
      <last-name>Bob</last-name>
      <award>Trenton Literary Review Honorable Mention</award>
    </author>
    <price>12</price>
  </book>
  <book style="textbook">
    <author>
      <first-name>Mary</first-name>
      <last-name>Bob</last-name>
      <publication>Selected Short Stories of
        <first-name>Mary</first-name>
        <last-name>Bob</last-name>
      </publication>
    </author>
    <editor>
      <first-name>Britney</first-name>
      <last-name>Bob</last-name>
    </editor>
    <price>55</price>
  </book>
  <book style="novel" id="myfave">
    <author>
      <first-name>Toni</first-name>
      <last-name>Bob</last-name>
      <degree from="Trenton U">B.A.</degree>
      <degree from="Harvard">Ph.D.</degree>
      <award>Pulitzer</award>
      <publication>Still in Trenton</publication>
      <publication>Trenton Forever</publication>
    </author>
    <price intl="Canada" exchange="0.7">6.50</price>
    <excerpt>
      <p>It was a dark and stormy night.</p>
      <p>But then all nights in Trenton seem dark and
      stormy to someone who has gone through what
      <emph>I</emph> have.</p>
      <definition-list>
        <term>Trenton</term>
        <definition>misery</definition>
      </definition-list>
    </excerpt>
  </book>
  <my:book xmlns:my="uri:mynamespace" style="leather" price="29.50">
    <my:title>Who's Who in Trenton</my:title>
    <my:author>Robert Bob</my:author>
  </my:book>
</bookstore>

目标 XML

<bookstore specialty="novel">
  <book style="History">
    <author>
      <first-name>Joe</first-name>
      <last-name>Bob</last-name>
      <award>Trenton Literary Review Honorable Mention</award>
    </author>
    <price>12</price>
  </book>
</bookstore>

结果 XML

<bookstore specialty="novel">
  <book style="autobiography">
    <author>
      <first-name>Joe</first-name>
      <last-name>Bob</last-name>
      <award>Trenton Literary Review Honorable Mention</award>
    </author>
    <price>12</price>
  </book>
  <book style="textbook">
    <author>
      <first-name>Mary</first-name>
      <last-name>Bob</last-name>
      <publication>Selected Short Stories of
        <first-name>Mary</first-name>
        <last-name>Bob</last-name>
      </publication>
    </author>
    <editor>
      <first-name>Britney</first-name>
      <last-name>Bob</last-name>
    </editor>
    <price>55</price>
  </book>
  <book style="novel" id="myfave">
    <author>
      <first-name>Toni</first-name>
      <last-name>Bob</last-name>
      <degree from="Trenton U">B.A.</degree>
      <degree from="Harvard">Ph.D.</degree>
      <award>Pulitzer</award>
      <publication>Still in Trenton</publication>
      <publication>Trenton Forever</publication>
    </author>
    <price intl="Canada" exchange="0.7">6.50</price>
    <excerpt>
      <p>It was a dark and stormy night.</p>
      <p>But then all nights in Trenton seem dark and
      stormy to someone who has gone through what
      <emph>I</emph> have.</p>
      <definition-list>
        <term>Trenton</term>
        <definition>misery</definition>
      </definition-list>
    </excerpt>
  </book>
</bookstore>

【问题讨论】:

  • 我很惊讶在您的 XPath 表达式中看到反斜杠。 XPath 总是使用正斜杠。大概这意味着您在此处显示的代码实际上是不可执行的。
  • 是的,这个示例代码是为了解释这个问题而写的。我已经替换了问题中的那些斜线

标签: .net xml xpath saxon


【解决方案1】:

我不确定您的简单 XPath 表达式是否需要 Saxon 和 XPath 2.0,并且我不确定您是否真的要删除目标中选择的所有元素,然后简单地将源中选择的元素插入为 @ 的子项987654321@ 但 Saxon 和 .NET 的 DOM API 的混合体将类似于

        Processor SaxonProcessor = new Processor();
        XPathCompiler Compiler = SaxonProcessor.NewXPathCompiler();

        XmlDocument sourceDomDoc = new XmlDocument();
        sourceDomDoc.Load("../../XMLFile1.xml");

        DocumentBuilder sBuilder = SaxonProcessor.NewDocumentBuilder();
        XdmNode sourceNode = sBuilder.Wrap(sourceDomDoc);

        XmlDocument targetDomDoc = new XmlDocument();
        targetDomDoc.Load("../../XMLFile2.xml");

        XdmNode targetNode = sBuilder.Wrap(targetDomDoc);



        string xPath = @"/bookstore/book";
        var sourceExp = Compiler.Compile(xPath).Load();
        sourceExp.ContextItem = sourceNode;

        var targetExp = Compiler.Compile(xPath).Load();
        targetExp.ContextItem = targetNode;

        var sourceXdmValue = sourceExp.Evaluate(); // Gives me source nodes
        var targetXdmValue = targetExp.Evaluate(); // Gives me target nodes to replace
        foreach (XdmNode toRemove in targetXdmValue)
        {
            XmlNode domToRemove = toRemove.getUnderlyingXmlNode();
            domToRemove.ParentNode.RemoveChild(domToRemove);
        }

        foreach (XdmNode tobeCopied in sourceXdmValue)
        {
            XmlNode copy = targetDomDoc.ImportNode(tobeCopied.getUnderlyingXmlNode(), true);
            targetDomDoc.DocumentElement.AppendChild(copy);
        }

        targetDomDoc.Save(Console.Out); // for debugging

但是,我同意在 XSLT 2.0 中执行此操作似乎是更好的方法,因为您已经使用 Saxon。

【讨论】:

    【解决方案2】:

    基本答案是,“解包”XPath 表达式返回的 XdmNode 值以获取底层 DOM 节点,然后使用 DOM 接口修改底层 XmlDocument 实例。因此,您实际上根本没有为此使用 Saxon API。

    但就我个人而言,我会采取完全不同的方式:我会在 XSLT 转换中完成整个事情。

    恐怕我无法为您提供执行此操作的实际代码,因为我不明白您的逻辑。为什么结果文档包含“源”中的所有书籍和杂志元素,但不包含 my:book 元素,而“目标”中什么也没有?

    【讨论】:

    • 感谢您的回答。我已经纠正了问题中的一些问题,特别是斜杠问题和结果 xml 中的杂志元素。如问题中所述,我想通过删除目标中的任何书籍元素来替换目标中的所有书籍元素。您能否提供有关如何使用 Unwrap 更新底层 XmlDocument 的更多详细信息?
    • 可以调用 XdmValue.GetList 来获取 XdmItem 对象的列表;如果该项目是一个节点,您可以将 XdmItem 转换为 XdmNode;如果节点是使用 Microsoft DOM 实现的,那么您可以调用 XdmNode.getUnderlyingXmlNode() 来获取 XmlNode。
    猜你喜欢
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-30
    • 1970-01-01
    相关资源
    最近更新 更多