Dan*_*ake 5 xml xslt xpath transform
我必须在循环的上下文中仅从XML文档中选择唯一记录<xsl:for-each>.我被Visual Studio限制为使用XSL 1.0.
<availList>
<item>
<schDate>2010-06-24</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>13:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-24</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>13:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-25</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>12:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-26</schDate>
<schFrmTime>13:00:00</schFrmTime>
<schToTime>14:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
<item>
<schDate>2010-06-26</schDate>
<schFrmTime>10:00:00</schFrmTime>
<schToTime>12:00:00</schToTime>
<variousOtherElements></variousOtherElements>
</item>
</availList>
Run Code Online (Sandbox Code Playgroud)
唯一性必须建立在三个子元素的值schDate,schFrmTime和schToTime.如果两个item元素对于所有三个子元素具有相同的值,则它们是重复的.在上面的XML中,第一项和第二项是重复的.其余的都是独特的.如上所述,每个项目包含我们不希望包括在比较中的其他元素."独特性"应该是这三个要素的一个因素,而仅仅是那些要素.
我试图通过以下方式实现这一目标:
availList/item[not(schDate = preceding:: schDate and schFrmTime = preceding:: schFrmTime and schToTime = preceding:: schToTime)]
Run Code Online (Sandbox Code Playgroud)
这背后的想法是选择没有前面元素的记录schDate,schFrmTime并且schToTime.但是,它的输出缺少最后一项.这是因为我的XPath实际上排除了所有子元素值在整个前一个文档中匹配的项目.没有单个item匹配所有最后一个项目的子元素 - 但由于每个元素的值单独存在于另一个项目中,因此最后一个项目将被排除.
通过将所有子值作为连接字符串与每个前面项的相同连接值进行比较,我可以得到正确的结果.有人知道我能做到这一点吗?
I. 作为单个 XPath 表达式:
/*/item[normalize-space() and not(. = preceding-sibling::item)]
Run Code Online (Sandbox Code Playgroud)
二. 使用键更高效(XSLT)实现:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kItemByVal" match="item" use="."/>
<xsl:template match="/">
<xsl:copy-of select=
"*/item[generate-id() = generate-id(key('kItemByVal', .))]
"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当应用于提供的 XML 文档时,I 和 II 都正确选择/复制以下节点:
<item><schDate>2010-06-24</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>13:00:00</schToTime></item>
<item><schDate>2010-06-25</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
<item><schDate>2010-06-26</schDate><schFrmTime>13:00:00</schFrmTime><schToTime>14:00:00</schToTime></item>
<item><schDate>2010-06-26</schDate><schFrmTime>10:00:00</schFrmTime><schToTime>12:00:00</schToTime></item>
Run Code Online (Sandbox Code Playgroud)
更新:如果<item>有其他孩子,则此转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kItemBy3Children" match="item"
use="concat(schDate, '+', schFrmTime, '+', schToTime)"/>
<xsl:template match="/">
<xsl:copy-of select=
"*/item[generate-id()
= generate-id(key('kItemBy3Children',
concat(schDate,
'+', schFrmTime,
'+', schToTime)
)
)
]
"/>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
产生想要的结果。