XSLT:根据这些值中的1个选择具有多个@class值的元素

时间:2013-12-19 21:46:56

标签: xslt xpath xslt-2.0 xpath-2.0

我有一个XML文档,它使用多个@class值,如下所示:

<html>
     <head>
        <title>This is the title.</title>
     </head>
     <body>
         <div class="sect1 rights">
             <p>This is the first paragraph.</p>
         </div>
     </body>
</html>

但是,如果存在@class值,则下面的XSLT不起作用。它只适用于<div class="rights">

<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:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>        
</xsl:template>

<xsl:template match="*[@class='rights']">
    <p>Rights have not cleared to show this material.</p>
</xsl:template>

我不认为这是模板问题的优先级(来自身份模板),因为我没有收到警告。有没有办法选择这个内容?除了“权利”之外,我不会总是知道除了“权限”之外还分配了哪些其他类值,因此我不能使用*[@class='sect1 rights'],因为sect1将在整个文档中发生变化。

2 个答案:

答案 0 :(得分:2)

在您的示例中,“class”属性只有单个值:字符串“sect1 rights”。如果要测试在该值中包含字符串“rights”,请使用:

<xsl:template match="*[contains(@class,'rights')]">

或者也许:

contains(concat(' ', @class, ' '), ' rights ')

如果您想确保“权利”作为一个单词存在(例如,不是“版权”的一部分)。

答案 1 :(得分:2)

由于您使用的是XSLT 2.0,因此可以使用tokenize()。这是concat()解决方案的一种更简单的形式@user3016153 gave(两种形式都比简单的contains()准确得多)。

<xsl:template match="*[tokenize(@class,'\s')='rights']">
    <p>Rights have not cleared to show this material.</p>
</xsl:template>

如果你想匹配多个可能的类,也很容易扩展:

<xsl:template match="*[tokenize(@class,'\s')=('rights','otherclass')]">
    <p>Rights have not cleared to show this material.</p>
</xsl:template>