使用XSLT将数据从一个XML文档复制到另一个XML文档

时间:2013-02-20 20:16:30

标签: xslt transformation

我必须将node元素的数据从file1.xml复制到file2.xml。 的 file1.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>

file2.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实现结果。

1 个答案:

答案 0 :(得分:4)

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

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

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

  • 可以使用document()函数来访问与当前文件不同的文件。如果XslCompiledTransform在使用文档函数时出错,我建议遵循此using document() function in .NET XSLT generates error。我正在使用不同的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>