2

我必须将节点元素的数据从 file1.xml 复制到 file2.xml。 文件1.xml

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <header>
    <AsofDate>31-Dec-2012</AsofDate>
    <FundName>This is Sample Fund</FundName>
    <Description>This is test description</Description>
  </header>
</root>

文件2.xml

<?xml version="1.0" encoding="utf-8" ?>
<root id="1">
  <header id="2">
    <AsofDate id="3"/>
    <FundName id="4" />
    <Description id="5" />
  </header>
</root>

将 file1.xml 合并到 file2.xml 后,结果应如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<root id="1">
  <header id="2">
    <AsofDate id="3">31-Dec-2012</AsofDate>
    <FundName id="4">This is Sample Fund</FundName>
    <Description id="5">This is test description</Description>
  </header>
</root>

我正在使用下面的 XSLT 来转换文件。

<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

下面是用于执行转换的代码:

    XslCompiledTransform tf = new XslCompiledTransform();
    tf.Load("TranFile.xsl");

    tf.Transform("file1.xml", "file2.xml");

但上面的代码是用 file1.xml 内容覆盖 file2 内容。这只是示例 XML。在实际情况下,我们不知道 xml 文件的节点名称和层次结构。但是文件和场景的任何结构都将完全相同。我是 XSLT 的新手,不确定这种方法是否正确。真的有可能通过 XSLT 实现结果吗?

4

1 回答 1

4

我发布的解决方案是在考虑以下内容的情况下编写的:

  • 唯一需要合并的是属性。文本和元素节点从 file1.xml 中出现时被复制。

  • @id 属性在 file2.xml 中没有按顺序编号,因此 file2.xml 中的 @id 可能是(例如)121 432 233 12 944 而不是 1 2 3 4 5。如果是后者,则不需要file2.xml 以生成所需的输出。

  • document() 函数可用于访问与当前文件不同的文件。如果在使用文档函数时 XslCompiledTransform 出现错误,我建议在 .NET XSLT 中使用 document() 函数来执行此操作会生成错误。我正在使用不同的 XSLT 处理器 (xsltproc),它工作正常。

此解决方案基于保留对外部文件的引用,因此每次我们处理 file1.xml 中的元素时,引用都会移动到指向 file2.xml 中的同一元素。可以这样做是因为根据问题,两个文件都呈现相同的元素层次结构。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="no"/>

    <!-- Match the document node as an entry point for matching the files -->
    <xsl:template match="/">
        <xsl:apply-templates select="node()">
            <xsl:with-param name="doc-context" select="document('file2.xml')/node()" />
        </xsl:apply-templates>
    </xsl:template>

    <!-- In this template we copy the elements and text nodes from file1.xml and
         we merge the attributes from file2.xml with the attributes in file1.xml -->
    <xsl:template match="node()">
        <!-- We use this parameter to keep track of where we are in file2.xml by
             mimicking the operations that we do in the current file. So we are at
             the same position in both files at the same time. -->
        <xsl:param name="doc-context" />

        <!-- Obtain current position in file1.xml so we know where to look in file2.xml -->
        <xsl:variable name="position" select="position()" />

        <!-- Copy the element node from the current file (file1.xml) -->
        <xsl:copy>
            <!-- Merge attributes from file1.xml with attributes from file2.xml -->
            <xsl:copy-of select="@*|$doc-context[position() = $position]/@*" />
            <!-- Copy text nodes and process children -->
            <xsl:apply-templates select="node()">
                <xsl:with-param name="doc-context" select="$doc-context/node()" />
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>
于 2013-02-20T23:49:56.540 回答