我有一个带有两个“数据集”数据的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。
答案 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>