在XSLT中提取默认属性的值

时间:2010-09-29 11:33:22

标签: xslt xpath

我有一个非常具体的问题,我希望能够提取元素的默认属性值,如下例所示。

输入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>

5 个答案:

答案 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>