<Root> <FirstName>Bob</FirstName> <LastName>Marley</LastName> <ID>BM1234</ID> <Songs> <Song> <EmptyElements></EmptyElements> <SongName>No woman no cry</SongName> <Year>1974</Year> <album></album> <studio></studio> <rating></rating> </Song> </Songs> </Root>
输出需要看起来像
<Root> <FirstName>Bob</FirstName> <LastName>Marley</LastName> <ID>BM1234</ID> <Songs> <Song> <EmptyElements>album, studio, rating</EmptyElements> <SongName>No woman no cry</SongName> <Year>1974</Year> </Song> </Songs> </Root>
所以基本上将所有空元素的逗号分隔列表放入EmptyElements标记中.
这种转变:<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:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="EmptyElements" priority="5"> <xsl:copy> <xsl:apply-templates mode="enumerate" select= "../*[not(self::EmptyElements) and not(node())]" /> </xsl:copy> </xsl:template> <xsl:template match="Songs/Song/*" mode="enumerate"> <xsl:value-of select="substring(',', not(position() = 1), 1)"/> <xsl:value-of select="name()"/> </xsl:template> <xsl:template match="Songs/Song/*[not(node())]"/> </xsl:stylesheet>
应用于提供的源XML文档时:
<Root> <FirstName>Bob</FirstName> <LastName>Marley</LastName> <ID>BM1234</ID> <Songs> <Song> <EmptyElements></EmptyElements> <SongName>No woman no cry</SongName> <Year>1974</Year> <album></album> <studio></studio> <rating></rating> </Song> </Songs> </Root>
产生想要的,正确的结果:
<Root> <FirstName>Bob</FirstName> <LastName>Marley</LastName> <ID>BM1234</ID> <Songs> <Song> <EmptyElements>album,studio,rating</EmptyElements> <SongName>No woman no cry</SongName> <Year>1974</Year> </Song> </Songs> </Root>
说明:
>选择执行时,标识规则将“按原样”复制匹配的节点
>匹配Songs / Song / * [not(node())]的模板,当选择执行时,不执行任何操作,这会导致“删除”(不复制)输出中的匹配节点.
>匹配EmptyElements的模板具有比上述“删除”模板更高的优先级,因此选择在任何EmptyElements元素上执行.
>将匹配的EmptyElements元素浅层复制到输出,然后通过将模板枚举模板应用于所有空的siblings-elements来生成其内容(正文).
>最后,模式枚举中的模板匹配Song元素的任何子元素,该元素是Songs元素的子元素.它由< xsl:apply-templates>选择执行.上面步骤4中的指令,仅适用于EmptyElements元素的空元素兄弟节点.此模板执行两项操作:a)输出逗号,如果这不是node-list中的第一个节点; b)输出匹配元素的名称.这样,输出EmptyElements元素的空兄弟元素的所有名称,用逗号分隔.
更新:
亲爱的读者,
我们有一个同伴的答案,这个问题以或简单地开头:
并且暗示它比这个答案中的代码更简单.
而不是告诉你这个答案比简单地简单:-answer,我总结了一些与简单相关的事实,你可以自己做出结论.在下表中,每个左子列中的值都是针对此的当前解决方案.每个右侧子列中的值仅适用于Or:-solution:
除此之外,简单地说: – 解决方案也具有潜在的性能和一定的可流动性问题 – 请参阅此片段:
<xsl:if test="position()!=last()"> <xsl:text>, </xsl:text> </xsl:if>
与当前解决方案使用的内容相比:
not(position() = 1)
见Dr. Michael Kay’s recommendation,后者是“比这更好的编码方式”,他解释了为什么:
“Why? Because however hard the optimizer works, the last() function is hard
work: it involves some kind of lookahead. With “position() ne last()” the
lookahead might be limited to one element, but it’s still a lot more
complicated than testing whether the position is 1.With streaming coming along, the latter formulation is also more likely to
be streamable (because lookahead is impossible with streaming).”
结论:每当有人告诉我们:“或者简单地说:”,在将他们的陈述视为理所当然之前采取一些指标是很好的…