使用XSLT 1.0,我需要在处理指令<?start?>
和<?end?>
之间对每个节点进行分组。此对外的节点应在输出处保持不变。
首先,我需要找到一种方法,如何只选择每个起始端对之间的节点。假设我们有一个示例输入XML:
<root>
abc
<?start?>
def<Highlighted bold="yes">
<Highlighted italic="yes">ghi</Highlighted>
</Highlighted>jkl
<?pi?>
<table>
<Caption>stu</Caption>
</table>vw
<?end?>
xy
<?start?>
abc <Caption>def</Caption> ghi
<?end?>
jkl
</root>
此外,我还需要在输出端的“开始 - 结束”交叉点之外设置节点。这意味着在输出处:a)起始端PI的交叉点处的节点将位于组元素b)交叉点外的任何节点将保持不变。请注意,输入文档也可能没有开始 - 结束处理指令对。
例如,根据给定的输入,输出应如下所示:
<root>
abc
<group>
def<Highlighted bold="yes">
<Highlighted italic="yes">ghi</Highlighted>
</Highlighted>jkl
<?pi?>
<table>
<Caption>stu</Caption>
</table>vw
</group>
xy
<group>
abc <Caption>def</Caption> ghi
</group>
jkl
<root>
此问题的一部分已在Finding all XML nodes between each two processing instructions中得到解答。但是我很难打印出group元素之外的节点而不重复任何节点。
答案 0 :(得分:2)
代码:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()[1]"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="processing-instruction('start')">
<group>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</group>
<xsl:apply-templates select="following-sibling::processing-instruction('end')[1]/following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="processing-instruction('end')"/>
</xsl:stylesheet>
此XSLT使用递归方法处理第一个子节点和第一个后续兄弟节点()。
第一个模板处理除开始和结束pis之外的所有节点。
第二个模板将group
元素添加到start pi和end pi之间的元素。第三个模板有助于删除结束pi。
答案 1 :(得分:0)
将root
的模板更改为
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="key('start', '') | processing-instruction('start') | node()[preceding-sibling::processing-instruction()[1][self::processing-instruction('end')]] | key('end', '')"/>
</xsl:copy>
</xsl:template>
所以整个代码变成
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="start" match="root/node()[not(self::processing-instruction('start'))]" use="generate-id(preceding-sibling::processing-instruction('start')[1])"/>
<xsl:key name="end" match="root/node()[not(self::processing-instruction('end'))]" use="generate-id(following-sibling::processing-instruction('end')[1])"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="key('start', '') | processing-instruction('start') | node()[preceding-sibling::processing-instruction()[1][self::processing-instruction('end')]] | key('end', '')"/>
</xsl:copy>
</xsl:template>
<xsl:template match="processing-instruction('start')">
<xsl:variable name="end" select="following-sibling::processing-instruction('end')[1]"/>
<xsl:variable name="following-start" select="key('start', generate-id())"/>
<xsl:variable name="preceding-end" select="key('end', generate-id($end))"/>
<xsl:variable name="intersect" select="$following-start[count(. | $preceding-end) = count($preceding-end)]"/>
<group>
<xsl:copy-of select="$intersect"/>
</group>
</xsl:template>
</xsl:stylesheet>
测试不是很好,但我希望它涵盖了pis之前,之间和之后的所有节点。
答案 2 :(得分:0)
即使我喜欢@Lingamurthy CS的递归解决方案 她的解决方案略有不同。
isValidJson(jsonstr)