Shi*_*hil 5 xslt xslt-2.0 xpath-2.0
这是xml的一个片段:
<sample>
<test>
<Cell1>John</Cell1>
<Cell2>A</Cell2>
<Cell4>xy</Cell4>
</test>
<test>
<Cell1>Jack</Cell1>
<Cell2>B</Cell2>
<Cell3>Red</Cell3>
<Cell6>10</Cell6>
</test>
<test>
<Cell1>John,Jade</Cell1>
<Cell2>A,Y</Cell2>
<Cell4>1</Cell4>
</test>
<test>
<Cell1>John,Jade</Cell1>
<Cell2>A B,X</Cell2>
<Cell3>Blue</Cell3>
</test>
</sample>
Run Code Online (Sandbox Code Playgroud)
如果Cell2包含逗号分割值并检查前面是否Cell2包含相同的值,同样如果Cell2包含空格则拆分值并检查前面是否Cell2包含相同的值 - >如果是,则忽略它.
这就是我想要输出的方式:
<Cell2>A</Cell2>
<Cell2>B</Cell2>
<Cell2>Y</Cell2>
<Cell2>X</Cell2>
Run Code Online (Sandbox Code Playgroud)
这是我写的xslt :(请查看评论)
<xsl:template match="sample">
<xsl:for-each select="test">
<xsl:choose>
<xsl:when test="contains(Cell2,',')">
<xsl:variable name="token1Cell2" select="tokenize(Cell2,',')"/>
<xsl:for-each select="$token1Cell2">
<xsl:choose>
<xsl:when test="contains(.,' ')">
<xsl:variable name="token2Cell2" select="tokenize(.,' ')"/>
<xsl:for-each select="$token2Cell2">
<!-- I tried to check if the preceding sibling element test/Cell2 contains the text that is not equal to the current text. But I know what I am doing is wrong as I am inside for-each tokenize. How to get the preceding-sibling? -->
<xsl:if test="preceding-sibling::test/
Cell2/text() != '.'">
<Cell2>
<xsl:value-of select="."/>
</Cell2>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:if test="preceding-sibling::test/Cell2/text() != '.'">
<Cell2>
<xsl:value-of select="."/>
</Cell2>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<Cell2>
<xsl:value-of select="Cell2"/>
</Cell2>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
我怎样才能实现输出?有任何想法吗??
只是这个简单的转变:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="distinct-values(/*/test/Cell2/tokenize(.,'[ ,]'))">
<Cell2><xsl:value-of select="."/></Cell2>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当应用于提供的XML文档时:
<sample>
<test>
<Cell1>John</Cell1>
<Cell2>A</Cell2>
<Cell4>xy</Cell4>
</test>
<test>
<Cell1>Jack</Cell1>
<Cell2>B</Cell2>
<Cell3>Red</Cell3>
<Cell6>10</Cell6>
</test>
<test>
<Cell1>John,Jade</Cell1>
<Cell2>A,Y</Cell2>
<Cell4>1</Cell4>
</test>
<test>
<Cell1>John,Jade</Cell1>
<Cell2>A B,X</Cell2>
<Cell3>Blue</Cell3>
</test>
</sample>
Run Code Online (Sandbox Code Playgroud)
产生想要的,正确的结果:
<Cell2>A</Cell2>
<Cell2>B</Cell2>
<Cell2>Y</Cell2>
<Cell2>X</Cell2>
Run Code Online (Sandbox Code Playgroud)
说明:
select属性中的XPath表达式xsl:for-each是理解的关键:
distinct-values(/*/test/Cell2/tokenize(.,'[ ,]'))
Run Code Online (Sandbox Code Playgroud)
这会产生所有标记化序列的不同值(字符串值) /*/test/Cell2
首先,如果您要对逗号或空格进行标记,那么您可以将标记组合到一个表达式中
<xsl:for-each select="tokenize(., ',|\s')">
Run Code Online (Sandbox Code Playgroud)
您可以做的是,首先匹配所有Cell2元素,使用模板标记内容,但将结果放入变量中
<xsl:variable name="cells">
<xsl:apply-templates select="test/Cell2"/>
</xsl:variable>
Run Code Online (Sandbox Code Playgroud)
然后您可以简单地使用xsl:for-each-group来迭代它们
<xsl:for-each-group select="$cells/Cell2" group-by="text()">
<xsl:copy-of select="."/>
</xsl:for-each-group>
Run Code Online (Sandbox Code Playgroud)
这是完整的 XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="sample">
<xsl:variable name="cells">
<xsl:apply-templates select="test/Cell2"/>
</xsl:variable>
<xsl:for-each-group select="$cells/Cell2" group-by="text()">
<xsl:copy-of select="."/>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="Cell2">
<xsl:for-each select="tokenize(., ',|\s')">
<Cell2>
<xsl:value-of select="."/>
</Cell2>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
当应用于示例 XML 时,输出如下
<Cell2>A</Cell2>
<Cell2>B</Cell2>
<Cell2>Y</Cell2>
<Cell2>X</Cell2>
Run Code Online (Sandbox Code Playgroud)