XSLT合并数据

时间:2015-10-01 13:51:45

标签: xslt

我有一个带有两个“数据集”数据的xml文件,我需要将其合并到显示旧版和新版的表中。我只是通过处理新数据来做到这一点,并且对于每一条新数据,抓住随附的旧数据。我的问题是如何在新集合中正确存储我的当前位置,以便我可以从旧集合中获取匹配数据。我遇到的真正挑战是嵌套元素,其中position()不那么有用。因此,给定以下简化的xml,我知道100%肯定会在New和Old中设置完美匹配的标记...

<doc>
   <New>
      <Para>New info 1</Para>
      <Para>New info 2</Para>
      <List>
         <Li>New Point 1</Li>
         <Li>New Point 2</Li>
         <Li>New Point 3</Li>
      </List>
      <Para>New info 3</Para>
      <List>
         <Li>New Point 4</Li>
         <Li>New Point 5</Li>
         <Li>New Point 6
            <List>
               <Li>New nested Point 1</Li>
               <Li>New nested Point 2</Li>
               <Li>New nested Point 3</Li>
            </List>
         </Li>
      </List>
   </New>
   <Old>
      <Para>Old info 1</Para>
      <Para>Old info 2</Para>
      <List>
         <Li>Old Point 1</Li>
         <Li>Old Point 2</Li>
         <Li>Old Point 3</Li>
      </List>
      <Para>Old info 3</Para>
      <List>
         <Li>Old Point 4</Li>
         <Li>Old Point 5</Li>
         <Li>Old Point 6
            <List>
               <Li>Old nested Point 1</Li>
               <Li>Old nested Point 2</Li>
               <Li>Old nested Point 3</Li>
            </List>
         </Li>
      </List>
   </Old>

我想在类似html的表中合并并输出信息。

  <table>
     <row>
        <entry>New Info 1</entry>
        <entry>Old Info 1</entry>
     </row>
     <row>
        <entry>New Info 2</entry>
        <entry>Old Info 2</entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New Point 1</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old Point 1</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New Point 2</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old Point 2</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New Point 3</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old Point 3</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>New Info 3</entry>
        <entry>Old Info 3</entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New Point 4</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old Point 4</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New Point 5</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old Point 5</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New Point 6</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old Point 6</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New nested Point 1</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old nested Point 1</li >
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New nested Point 2</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old nested Point 2</li>
           </list>
        </entry>
     </row>
     <row>
        <entry>
           <list>
              <li>New nested Point 3</li>
           </list>
        </entry>
        <entry>
           <list>
              <li>Old nested Point 3</li>
           </list>
        </entry>
     </row>
  </table>

只有嵌套元素才有问题。对于其他一切,我可以在&lt; New&gt;中存储我的位置。并在相应的&lt; Old&gt;上应用模板数据,但嵌套时position()变得不那么有用。

有关如何在&lt; New&gt;中有效存储我的位置的任何想法这样我就可以处理匹配的&lt; Old&gt;元件?我正在使用XSLT 1。

1 个答案:

答案 0 :(得分:0)

由于您的示例仅处理每个分支中的顶级元素,因此可以通过以下方式完成请求的结果:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="old" match="id" use="." />

<xsl:variable name="old" select="/doc/Old" />

<xsl:template match="/doc">

    <table>
        <xsl:apply-templates select="New/Para | New/List"/>
    </table>
</xsl:template>

<xsl:template match="Para">
    <xsl:variable name="i" select="count(preceding-sibling::Para)" />
    <row>
        <entry>
            <xsl:value-of select="."/>
        </entry>
        <entry>
            <xsl:value-of select="$old/Para[$i + 1]"/>
        </entry>
    </row>
</xsl:template>

<xsl:template match="List">
    <xsl:variable name="i" select="count(preceding-sibling::List)" />
    <row>
        <entry>
            <xsl:copy-of select="."/>
        </entry>
        <entry>
            <xsl:copy-of select="$old/List[$i + 1]"/>
        </entry>
    </row>
</xsl:template>

</xsl:stylesheet>

我认为,将各个叶节点按其在各自树中的位置进行匹配会更加复杂。

编辑:

  

不幸的是,我确实需要匹配各个节点。

正如我所说,这将变得更加复杂 - 尤其是因为您无法使用扩展函数将字符串动态评估为路径表达式。

在这里,我们将对Old分支中的节点进行初步传递,并为它们分配path属性。这将使我们能够在处理New分支中的节点时通过此属性调用它们以获得最终输出:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<!-- first-pass -->
<xsl:variable name="old">
    <xsl:apply-templates select="/doc/Old" mode="old"/>
</xsl:variable>

<xsl:variable name="old-set" select="exsl:node-set($old)" />

<xsl:template match="Para | Li" mode="old">
    <node>
        <xsl:attribute name="path">
            <xsl:for-each select="ancestor-or-self::*">
                <xsl:value-of select="name()" />
                <xsl:variable name="i" select="count(preceding-sibling::*[name()=name(current())])" />
                <xsl:text>[</xsl:text>
                <xsl:value-of select="count(preceding-sibling::*[name()=name(current())])" />
                <xsl:text>]</xsl:text>
                <xsl:if test="position()!=last()">
                    <xsl:text>/</xsl:text>
                </xsl:if>
            </xsl:for-each>
        </xsl:attribute>
        <xsl:value-of select="text()"/>
    </node>
    <xsl:apply-templates select="*" mode="old"/>
</xsl:template>

<!-- output -->
<xsl:template match="/doc">
    <table>
        <xsl:apply-templates select="New"/>
    </table>
</xsl:template>

<xsl:template match="Para | Li">
    <xsl:variable name="path">
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="name()" />
            <xsl:variable name="i" select="count(preceding-sibling::*[name()=name(current())])" />
            <xsl:text>[</xsl:text>
            <xsl:value-of select="count(preceding-sibling::*[name()=name(current())])" />
            <xsl:text>]</xsl:text>
            <xsl:if test="position()!=last()">
                <xsl:text>/</xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <xsl:variable name="old-path" select="concat('doc[0]/Old[0]/', substring-after($path, 'doc[0]/New[0]/'))" />
    <row>   
        <entry>
            <xsl:value-of select="text()"/>
        </entry>
        <entry>
            <xsl:value-of select="$old-set/node[@path=$old-path]"/>
        </entry>
    </row>
    <xsl:apply-templates select="*"/>
</xsl:template>

</xsl:stylesheet>

<强>结果

<?xml version="1.0" encoding="UTF-8"?>
<table>
   <row>
      <entry>New info 1</entry>
      <entry>Old info 1</entry>
   </row>
   <row>
      <entry>New info 2</entry>
      <entry>Old info 2</entry>
   </row>
   <row>
      <entry>New Point 1</entry>
      <entry>Old Point 1</entry>
   </row>
   <row>
      <entry>New Point 2</entry>
      <entry>Old Point 2</entry>
   </row>
   <row>
      <entry>New Point 3</entry>
      <entry>Old Point 3</entry>
   </row>
   <row>
      <entry>New info 3</entry>
      <entry>Old info 3</entry>
   </row>
   <row>
      <entry>New Point 4</entry>
      <entry>Old Point 4</entry>
   </row>
   <row>
      <entry>New Point 5</entry>
      <entry>Old Point 5</entry>
   </row>
   <row>
      <entry>New Point 6
            </entry>
      <entry>Old Point 6
            </entry>
   </row>
   <row>
      <entry>New nested Point 1</entry>
      <entry>Old nested Point 1</entry>
   </row>
   <row>
      <entry>New nested Point 2</entry>
      <entry>Old nested Point 2</entry>
   </row>
   <row>
      <entry>New nested Point 3</entry>
      <entry>Old nested Point 3</entry>
   </row>
</table>