存在某些属性(或不存在)的复制节点

时间:2018-05-01 23:33:13

标签: xml xslt xpath xslt-1.0 xslt-2.0

我目前有这个xsl工作得很好

run()

这实际上重写了我的XML,删除了除Ccy之外的所有属性。但是,我现在需要包含名称为“name”的属性。我喜欢联合我想要保留的属性名称:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()">
        <xsl:copy copy-namespaces="no">
            <xsl:copy-of select="@Ccy"/>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

或者,理想情况下,复制所有属性EXCEPT

<xsl:copy-of select="@Ccy | @name"/>

任何想法??

3 个答案:

答案 0 :(得分:3)

您可以使用以下样式表:

<强> INPUT:

$more input.xml 
<?xml version="1.0"?>
<a>
  <b Ccy="123" name="test1" BadAttyNameTest="toRemove1" BadAttyNameTestt="toRemovee1" other="hey1">toto</b>
  <b Ccy="456" name="test2" BadAttyNameTest="toRemove2" BadAttyNameTestt="toRemovee2" other="hey2">abc</b>
  <b Ccy="789" name="test3" BadAttyNameTest="toRemove3" BadAttyNameTestt="toRemovee3" other="hey3">uvw</b>
</a>

<强> UNION:

::::::::::::::
inputUnion.xsl
::::::::::::::
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()">
        <xsl:copy copy-namespaces="no">
            <xsl:copy-of select="@Ccy | @name"/>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

OUTPUT UNION:

$xsltproc inputUnion.xsl input.xml 
<a>
  <b Ccy="123" name="test1">toto</b>
  <b Ccy="456" name="test2">abc</b>
  <b Ccy="789" name="test3">uvw</b>
</a>

它只会复制属性@Ccy | @name的并集,其他属性不会被考虑在内。

<强>除了:

::::::::::::::
inputNOT.xsl
::::::::::::::
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="node()">
        <xsl:copy copy-namespaces="no">
            <xsl:copy-of select="@*[not(starts-with(name(),'BadAttyName'))]"/>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

OUTPUT EXCEPT:

$xsltproc inputNOT.xsl input.xml 
<a>
  <b Ccy="123" name="test1" other="hey1">toto</b>
  <b Ccy="456" name="test2" other="hey2">abc</b>
  <b Ccy="789" name="test3" other="hey3">uvw</b>
</a>

语法@*[not(starts-with(name(),'BadAttyName'))]将采用满足括号中条件的所有属性。条件是不以BadAttyName开头的所有元素,这是通过组合not()starts-with()创建的。

答案 1 :(得分:2)

XSLT 2.0允许

<xsl:copy-of select="@* except @badAttName"/>

当然它也允许

<xsl:copy-of select="@* except @*[startswith(name(), 'badAttName')]"/>

但对于这种特殊情况,使用@*[not(....)]同样有效。

答案 2 :(得分:2)

XPath 2及更高版本(这是您在XSLT 2及更高版本中使用的表达式语言)确实有一个except运算符,因此您可以使用例如<xsl:copy-of select="@* except @foo"/>复制除foo属性之外的所有属性,例如<xsl:copy-of select="@* except (@foo, @bar)"/>复制除foobar之外的所有属性。

由于您要排除以特定前缀开头的属性,您可以使用<xsl:copy-of select="@* except @*[matches(local-name(), '^BadAttyName')]"/>,尽管已经建议的解决方案使用<xsl:copy-of select="@*[not(matches(local-name(), '^BadAttyName'))]"/>否定条件会更紧凑,在这种情况下可能更容易。