我正在使用Saxon HE 9-4-0-3J。我的意图是使用select
上的xsl:apply-templates
属性迭代每个<RECORD>
元素,但只处理xml中的一个<RECORD>
元素。
XML
<ENVELOPE>
<PRODUCT>
<HEAD><FLAG>No</FLAG></HEAD>
<BODY>
<RECORD><Value>9</Value></RECORD>
<RECORD><Value>10</Value></RECORD>
<MISC>9</MISC>
</BODY>
</PRODUCT>
xslt 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/ENVELOPE">
<Interface>
<Data><xsl:apply-templates select="PRODUCT"/></Data>
</Interface>
</xsl:template>
<xsl:template match="PRODUCT">
<xsl:choose>
<xsl:when test="HEAD/FLAG='Yes'">
<xsl:attribute name="Match">Affirmative</xsl:attribute>
<xsl:apply-templates select="BODY/RECORD" mode="affr"/>
</xsl:when>
<xsl:when test="HEAD/FLAG='No'">
<xsl:attribute name="Match">Negative</xsl:attribute>
<xsl:apply-templates select="BODY/RECORD" mode="neg"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="RECORD" mode="affr">
<xsl:attribute name="Value"><xsl:value-of select="Value"/></xsl:attribute>
</xsl:template>
<xsl:template match="RECORD" mode="neg">
<xsl:attribute name="Value"><xsl:value-of select="Value"/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
输出
<Interface>
<Data Match="Negative" Value="9"/> <!-- this line doesn't appear, I want it to -->
<Data Match="Negative" Value="10"/>
</Interface>
答案 0 :(得分:2)
匹配<DATA...>
时会生成<ENVELOPE...>
输出标记,因此只能输出其中一个。任何<xsl:attribute>
指令只会添加到此输出标记,以后的值会覆盖之前的值。
您必须明确生成要输出的DATA
标记,如:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/ENVELOPE">
<Interface>
<xsl:apply-templates select="PRODUCT"/>
</Interface>
</xsl:template>
<xsl:template match="PRODUCT">
<xsl:variable name="flag">
<xsl:choose>
<xsl:when test="HEAD/FLAG='Yes'">Affirmative</xsl:when>
<xsl:when test="HEAD/FLAG='No'">Negative</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:apply-templates select="BODY/RECORD">
<xsl:with-param name="flag"><xsl:value-of select="$flag"/></xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="RECORD">
<xsl:param name="flag"/>
<Data Value="{Value}" Match="{$flag}"/>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:2)
问题是您要创建两个名称相同的属性 - Value
。在格式良好的XML文档中,元素不能具有多个具有相同名称的属性。
引用W3C XSLT 2.0 Specification (这在XSLT 1.0中也是如此):
9。如果结果序列中的属性A与结果序列中稍后出现的另一个属性B具有相同的名称,则 从结果序列中删除属性A.
因此,每当XSLT为一个元素生成多个具有相同名称的属性时,只将最后一个属性复制到输出中 - 这就是您所看到的。
这是一个简短的解决方案(只有两个模板,没有条件,没有参数):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vDoc" select="/"/>
<xsl:variable name="vMatch" select=
"('Affirmative', 'Negative')[2 - number($vDoc/*/*/HEAD/FLAG eq 'Yes')]"/>
<xsl:template match="/*">
<Interface>
<xsl:apply-templates select="*/BODY/RECORD"/>
</Interface>
</xsl:template>
<xsl:template match="RECORD">
<Data Match="{$vMatch}" Value="{Value}"/>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<ENVELOPE>
<PRODUCT>
<HEAD>
<FLAG>No</FLAG>
</HEAD>
<BODY>
<RECORD>
<Value>9</Value>
</RECORD>
<RECORD>
<Value>10</Value>
</RECORD>
<MISC>9</MISC>
</BODY>
</PRODUCT>
</ENVELOPE>
产生了想要的正确结果:
<Interface>
<Data Match="Negative" Value="9"/>
<Data Match="Negative" Value="10"/>
</Interface>