我正在改进一些我通过使用XSLT进行清理而继承的XML,但我正在努力解决一个问题。看起来像这样:
<rules>
<if condition="equals" arg1="somevar" arg2="1"/>
<elseif condition="equals" arg1="somevar" arg2="2"/>
<elseif condition="equals" arg1="somevar" arg2="3"/>
<else/>
<if condition="equals" arg1="somevar" arg2="4"/>
<else/>
</rules>
这看起来很难用XSD验证,所以我想把它变成这样的东西 - 想法?
<rules>
<conditionSet>
<if condition="equals" arg1="somevar" arg2="1"/>
<elseif condition="equals" arg1="somevar" arg2="2"/>
<elseif condition="equals" arg1="somevar" arg2="3"/>
<else/>
</conditionSet>
<conditionSet>
<if condition="equals" arg1="somevar" arg2="4"/>
<else/>
</conditionSet>
</rules>
答案 0 :(得分:1)
按其前一个elseif
元素分组else
和if
元素:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="block" match="elseif|else"
use="generate-id(preceding-sibling::if[1])"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="rules">
<xsl:copy>
<xsl:apply-templates select="@*|
node()[not(self::elseif or self::else)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="if">
<conditionSet>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:apply-templates select="key('block', generate-id())"/>
</conditionSet>
</xsl:template>
</xsl:stylesheet>
此样式表生成请求的输出。
说明:xsl:key
将每个if
元素与其后续相关元素相关联,以便稍后当我们匹配if
时,我们可以简单地包装并复制整套。
答案 1 :(得分:1)
这是一个有趣的XSLT挑战。但是,呃,为什么要再次更改XML呢?输入中的模式可以通过正则表达式轻松定义,即
(if, elseif*, else)*
因此可以很容易地使用XSD进行验证。
改变可能是值得的 - 一位经验丰富的词汇设计师(Lynne A. Price)曾告诉我,组中的任何重复操作符都是自动怀疑的,并且通常意味着该组应该被元素替换。我想,她会批准你的改变。但有意义的是,改变的基本原理必须是更容易处理,而不是更容易验证。
答案 2 :(得分:0)
还有一个:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/rules">
<xsl:copy>
<xsl:apply-templates select="if"/>
</xsl:copy>
</xsl:template>
<xsl:template match="if">
<conditionSet>
<xsl:copy-of select="."/>
<xsl:apply-templates select="
following-sibling::*[not(self::if)
and generate-id(preceding-sibling::if[1])
= generate-id(current())]
"/>
</conditionSet>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 3 :(得分:0)
<强>予。更简单,更简洁的XSLT 1.0解决方案:
<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="kFollowing" match="elseif|else"
use="generate-id(preceding-sibling::if[1])"/>
<xsl:template match="/*">
<rules>
<xsl:apply-templates select="if"/>
</rules>
</xsl:template>
<xsl:template match="if">
<conditionSet>
<xsl:copy-of select=".|key('kFollowing', generate-id())"/>
</conditionSet>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<rules>
<if condition="equals" arg1="somevar" arg2="1"/>
<elseif condition="equals" arg1="somevar" arg2="2"/>
<elseif condition="equals" arg1="somevar" arg2="3"/>
<else/>
<if condition="equals" arg1="somevar" arg2="4"/>
<else/>
</rules>
产生了想要的正确结果:
<rules>
<conditionSet>
<if condition="equals" arg1="somevar" arg2="1"/>
<elseif condition="equals" arg1="somevar" arg2="2"/>
<elseif condition="equals" arg1="somevar" arg2="3"/>
<else/>
</conditionSet>
<conditionSet>
<if condition="equals" arg1="somevar" arg2="4"/>
<else/>
</conditionSet>
</rules>
<强> II。更简单,更简洁的XSLT 2.0解决方案:
<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="/*">
<rules>
<xsl:for-each-group select="*" group-starting-with="if">
<conditionSet>
<xsl:sequence select="current-group()"/>
</conditionSet>
</xsl:for-each-group>
</rules>
</xsl:template>
</xsl:stylesheet>
将此转换应用于同一XML文档(上图)时,会生成相同的正确结果:
<rules>
<conditionSet>
<if condition="equals" arg1="somevar" arg2="1"/>
<elseif condition="equals" arg1="somevar" arg2="2"/>
<elseif condition="equals" arg1="somevar" arg2="3"/>
<else/>
</conditionSet>
<conditionSet>
<if condition="equals" arg1="somevar" arg2="4"/>
<else/>
</conditionSet>
</rules>