Xslt 当属性具有特定值时从元素中移除属性

Xslt 当属性具有特定值时从元素中移除属性,xslt,xsd,xslt-2.0,Xslt,Xsd,Xslt 2.0,我正在编写一个样式表来“规范化”XML模式,以便比较它们。它将按名称、顺序属性(按固定顺序)等对顶级元素进行排序。这是到目前为止我对属性所做的: <xsl:template match="xsd:attribute"> <xsl:copy> <xsl:copy-of select="@name"/> <xsl:copy-of select="@type"/> <xsl:cop

我正在编写一个样式表来“规范化”XML模式,以便比较它们。它将按名称、顺序属性(按固定顺序)等对顶级元素进行排序。这是到目前为止我对属性所做的:

<xsl:template match="xsd:attribute">
    <xsl:copy>      
        <xsl:copy-of select="@name"/>
        <xsl:copy-of select="@type"/>
        <xsl:copy-of select="@ref"/>
        <xsl:copy-of select="@use"/>
        <xsl:copy-of select="@default"/>
        <xsl:apply-templates select="@*">
            <xsl:sort select="name()"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>

现在,我还想删除冗余属性。例如,应该删除
use=“optional”
,因为
optional
是默认值


因此,我的问题是:当
属性的值为
optional
时,为了删除
use
属性,增强上述代码的最简单方法是什么

@JohnBollinger和@MartinHonnen正确地指出,
@*
条件将插入所有属性,甚至是上面选择的属性。因此,必须改进条件。还有人指出,根据该规范,无法确保属性的顺序。他们被订购的事实只是我的处理器(Saxon9He)如何工作的一个假象。不过我对这个没意见。以下是我得出的解决方案:

<xsl:template match="xsd:attribute">
    <xsl:copy>
        <xsl:copy-of select="@name" />
        <xsl:copy-of select="@type" />
        <xsl:copy-of select="@ref" />
        <xsl:copy-of select="@use[string() != 'optional']" />
        <xsl:copy-of select="@default" />
        <xsl:apply-templates select="@*[name(.) != 'use']">
            <xsl:sort select="name()" />
        </xsl:apply-templates>
        <xsl:apply-templates select="node()" />
    </xsl:copy>
</xsl:template>


我没有将其他属性名称添加到
@*
上的负过滤器中,因为Saxon不会复制属性,即使它被
@*
子句重新插入,也不会按要求的顺序保留它们。因此,这确实以最少的努力满足了我目前的需求,即使它不是一个通用的解决方案(我实际上并不需要)。

@JohnBollinger和@MartinHonnen正确地指出,
@*
条件将插入所有属性,甚至是上面选择的属性。因此,必须改进条件。还有人指出,根据该规范,无法确保属性的顺序。他们被订购的事实只是我的处理器(Saxon9He)如何工作的一个假象。不过我对这个没意见。以下是我得出的解决方案:

<xsl:template match="xsd:attribute">
    <xsl:copy>
        <xsl:copy-of select="@name" />
        <xsl:copy-of select="@type" />
        <xsl:copy-of select="@ref" />
        <xsl:copy-of select="@use[string() != 'optional']" />
        <xsl:copy-of select="@default" />
        <xsl:apply-templates select="@*[name(.) != 'use']">
            <xsl:sort select="name()" />
        </xsl:apply-templates>
        <xsl:apply-templates select="node()" />
    </xsl:copy>
</xsl:template>


我没有将其他属性名称添加到
@*
上的负过滤器中,因为Saxon不会复制属性,即使它被
@*
子句重新插入,也不会按要求的顺序保留它们。因此,即使这不是一个通用的解决方案(我实际上并不需要),它也能以最少的努力满足我目前的需求。

属性在XSLT/XPath/XQuery数据模型中没有排序。另外,您希望通过对某些属性使用不同的
copy of
,然后将模板应用于所有属性来实现什么?我建议使用
apply templates
而不是
copy of
来转换属性,当指定的属性实际上不存在于上下文节点上时,
的复制将失败。然后,每个属性模板还可以为您提供适当的杠杆,用于忽略采用默认值的属性——在这种情况下,它们可以转换为零。它按照列出的顺序对指定的属性进行排序(因此,首先是
名称
,然后是
类型
,然后是
参考
,等等)。任何其他未明确命名的属性都将按名称排序(这是
apply templates select=“@*”
所做的)。否,@pegasus。首先,属性顺序在相关数据模型中不重要。如果您碰巧按照
元素副本出现的词法顺序可靠地获取属性,那么这是特定XSLT处理器的一个特征,而不是XSLT语言提供的保证。其次,
apply templates
将转换所有属性,不仅仅是那些尚未成为
复制
元素主题的属性。您的
应用模板
处理所有属性,包括您已经尝试输出的属性,这样,由于WinSatAttribute中的第9点,应用模板的最后一步不会在XSLT/XPath/XQuery数据模型中排序。另外,您希望通过对某些属性使用不同的
copy of
,然后将模板应用于所有属性来实现什么?我建议使用
apply templates
而不是
copy of
来转换属性,当指定的属性实际上不存在于上下文节点上时,
的复制将失败。然后,每个属性模板还可以为您提供适当的杠杆,用于忽略采用默认值的属性——在这种情况下,它们可以转换为零。它按照列出的顺序对指定的属性进行排序(因此,首先是
名称
,然后是
类型
,然后是
参考
,等等)。任何其他未明确命名的属性都将按名称排序(这是
apply templates select=“@*”
所做的)。否,@pegasus。首先,属性顺序在相关数据模型中不重要。如果您碰巧按照
元素副本出现的词法顺序可靠地获取属性,那么这是特定XSLT处理器的一个特征,而不是XSLT语言提供的保证。其次,
apply templates
将转换所有属性,不仅仅是那些尚未成为<代码>元素副本主题的属性。您的<代码>应用模板<代码>处理所有属性,包括您已经尝试输出的属性,这样,由于wins<代码>选择=“@*[name(!='use']”中的第9点,应用模板的最后一步就开始了
可以优雅地写成XSLT/XPath 2及更高版本中的
select=“@*除了@use”
select=“@*[name(.)!='use']”可以是