考虑这个question about beautiful XSL但更具体,我应该如何重构这个XSL以利用应用模板和/或密钥。
我倾向于“过度使用”for-each元素来控制源的上下文,我可以想象apply-templates可以提供帮助。尽管有很多Google,但我仍然不明白如何在多个模板中控制上下文。
在下面的示例中,如何通过重构来减少重复的XPath段?
<xsl:template match="/">
<xsl:element name="Body">
<xsl:element name="Person">
<xsl:if test="/source/dbSrc/srv/v[@name='name']/text()='false'">
<xsl:element name="PhoneNumber" />
<xsl:element name="Zip">
<xsl:value-of
select="/source/req[1]/personal-info/address-info/zip-code" />
</xsl:element>
</xsl:if>
<xsl:if test="/source/dbSrc/srv/v[@name='name']/text()='true'">
<xsl:element name="PhoneNumber" />
<xsl:element name="Zip">
<xsl:value-of select="/source/req[3]/personal-info/address-info/zip-code" />
</xsl:element>
</xsl:if>
</xsl:element>
</xsl:template>
答案 0 :(得分:1)
重构给定代码的一种初始方法如下:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Body>
<Person>
<PhoneNumber/>
<Zip>
<xsl:apply-templates select=
"/*/dbSrc/srv/v[@name='name']"/>
</Zip>
</Person>
</Body>
</xsl:template>
<xsl:template match="v[@name='name' and .='true']">
<xsl:value-of select=
"/*/req[3]/personal-info/address-info/zip-code"/>
</xsl:template>
<xsl:template match="v[@name='name' and .='false']">
<xsl:value-of select=
"/*/req[1]/personal-info/address-info/zip-code"/>
</xsl:template>
</xsl:stylesheet>
请注意:重构的代码不包含任何条件xslt说明。
进一步的重构可以让我们摆脱最后的模板,因为在这种情况下实际上并不需要额外的模板 - 代码只创建一个元素并依赖于一个条件:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vCond" select=
"/*/dbSrc/srv/v[@name='name']/text()='true'"/>
<xsl:variable name="vInd" select=
"3*$vCond + 1*not($vCond)"/>
<xsl:template match="/">
<Body>
<Person>
<PhoneNumber/>
<Zip>
<xsl:value-of select=
"/*/req[position()=$vInd]
/personal-info/address-info/zip-code"/>
</Zip>
</Person>
</Body>
</xsl:template>
</xsl:stylesheet>
注意:我们假设/*/dbSrc/srv/v[@name='name']/text()
只有两个可能的值:'true'
或'false'
答案 1 :(得分:1)
在XSLT 2.0中,我将其写为:
<xsl:template match="/">
<Body>
<Person>
<PhoneNumber/>
<Zip>
<xsl:variable name="index" as="xs:integer"
select="if (/source/dbSrc/srv/v[@name='name']='true') then 3 else 1"/>
<xsl:value-of select="/source/req[$index]/personal-info/address-info/zip-code"/>
</Zip>
</Person>
</Body>
</xsl:template>
使用1.0时,xsl:变量会变得有点复杂,但不会相同。
注意使用文字结果元素和变量来减小代码的大小;也避免使用“/ text()”,这几乎总是不好的做法。
这里使用模板规则的里程很少,因为您使用的输入数据非常少,而且您似乎确切地知道在哪里找到它。如果您想要更准确地了解您在源中查找的位置,那么模板规则就会自成一体:它们有助于使代码更容易适应变化和输入的变化。但是,如果没有看到来源并了解更多背景知识,我们无法告诉您需要哪种灵活性。索引“1”和“3”的硬编码对我来说似乎是一个危险的信号,但只有你能判断出来。