我有一个非常具体的问题,我希望能够提取元素的默认属性值,如下例所示。
输入XML中的每个项目都包含多个子名称元素,一个用于表示主要名称,即默认属性值(type ='main')和另一个辅助名称(type ='short')。主要名称没有指定属性值“main”。下面是一个示例输入XML,其中第一个名称元素被故意注释掉以进一步说明问题:
<?xml version="1.0"?>
<food_list>
<food_item>
<!--name>Apple</name-->
<name type="short">APL</name>
</food_item>
<food_item>
<name>Asparagus</name>
<name type="short">ASP</name>
</food_item>
<food_item>
<name>Cheese</name>
<name type="short">CHS</name>
</food_item>
</food_list>
NameType的XSD如下所示:
<complexType name="NameType">
<simpleContent>
<extension base="TextualBaseType">
<attribute name="type" use="optional" default="main">
<simpleType>
<restriction base="NMTOKEN">
<enumeration value="main"/>
<enumeration value="short"/>
<enumeration value="alternative"/>
</restriction>
</simpleType>
</attribute>
</extension>
</simpleContent>
</complexType>
转换输入XML并提取主要名称和短名称的XSLT如下:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="food_list">
<table>
<tr style="background-color:#ccff00">
<th>Food Name</th>
<th>Food Short Name</th>
</tr>
<xsl:for-each select="food_item">
<tr style="background-color:#00cc00">
<td><xsl:value-of select="name"/></td>
<td><xsl:value-of select="name[@type='short']"/></td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
当转换输入XML时,第一个食物项的主要名称从type ='short'的元素中被错误地拾取。 问题:在定义默认元素时,如何将xslt中第一个值语句限制为仅选择名称值?< / p>
答案 0 :(得分:2)
问题:你如何限制 xslt中的第一个value-of语句 只在a时选择名称值 默认元素是否已定义?
XSLT 1.0不支持架构,可能不支持内部DTD。
XSLT 2.0基本处理器不支持架构。
总而言之,您需要一个支持XSLT 2.0架构的。
解决方法是测试不存在此属性以将此元素视为已定义默认属性:
name[not(@type) or @type='main']
答案 1 :(得分:1)
XSLT不了解XSD架构,因此您需要在样式表中添加信息(默认值为默认值)。匹配的xsl:if会解决问题。当然,如果更改XSD,则必须更新样式表。使用模式更灵活的唯一方法是从样式表中读取和分析模式,但这将非常困难,您必须限制模式中的可能更改以简化问题。
答案 2 :(得分:1)
你遇到的问题是<xsl:value-of select="name" />
将选择任何名称元素,无论它是否具有属性,包括具有“短”类型的属性;您需要将其限制为仅具有type属性的那些,或者type属性具有值'main'的那些。
你可以这样做:
<xsl:value-of select="name[not(@type) or @type='main']" />
。
当然,这并未明确引用架构,但由于架构本身就是一个XML文档,因此您可以使用'main'
函数替换document()
对架构的引用;如果你选择这样做,我建议将值存储在xslt根目录中的变量中,所以它只获取一次。例如:
<xsl:variable name="defaultType" select="document('<schema url>')//complexType[@name='NameType']/simpleContent/extension/attribute/@default" />
然后,您只需将'main'
的引用替换为$defaulttype
。
答案 3 :(得分:0)
如果我正确理解了您的问题,您可以在<xsl:if>
周围放置<xsl:value-of>
,检查该名称是否没有@type
属性。 (可能类似于<xsl:if test="not(name[@type])">
)
答案 4 :(得分:0)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="food_list">
<table>
<tr style="background-color:#ccff00">
<th>Food Name</th>
<th>Food Short Name</th>
</tr>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template match="food_item">
<tr style="background-color:#00cc00">
<td><xsl:value-of select=
"concat(name[not(@type)],
name[@type='main'],
substring('some hardcoded default',
1
div
(not(name[not(@type)])
and
not(name[@type='main'])
)
)
)
"/></td>
<td><xsl:value-of select="name[@type='short']"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
应用于以下XML文档(基于提供的,但略微放大以表示更多可能的情况):
<food_list>
<food_item>
<!--name>Apple</name-->
<name type="short">APL</name>
<name type="alternative">Gala APL</name>
</food_item>
<food_item>
<name>Asparagus</name>
<name type="short">ASP</name>
</food_item>
<food_item>
<name>Cheese</name>
<name type="short">CHS</name>
</food_item>
<food_item>
<name type="main">Grapes</name>
<name type="short">GPS</name>
</food_item>
</food_list>
生成想要的正确结果:
<table>
<tr style="background-color:#ccff00">
<th>Food Name</th>
<th>Food Short Name</th>
</tr>
<tr style="background-color:#00cc00">
<td>some hardcoded default</td>
<td>APL</td>
</tr>
<tr style="background-color:#00cc00">
<td>Asparagus</td>
<td>ASP</td>
</tr>
<tr style="background-color:#00cc00">
<td>Cheese</td>
<td>CHS</td>
</tr>
<tr style="background-color:#00cc00">
<td>Grapes</td>
<td>GPS</td>
</tr>
</table>