【问题标题】:copy node where certain attributes are present (or not present)存在(或不存在)某些属性的复制节点
【发布时间】:2018-10-12 00:10:35
【问题描述】:

我目前有这个运行良好的 xsl

<?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>

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

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

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

<xsl:copy-of select="!@BadAttyName"/>

有什么想法吗??

【问题讨论】:

  • 看起来我回答了我自己的问题。 似乎有效。不过,为了“有趣”,除了以 BadAttyName 开头的属性之外,如何复制所有内容? ??
  • 能否添加一个 XML 示例?

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


【解决方案1】:

您可以使用以下样式表:

输入:

$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>

联合:

::::::::::::::
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>

输出联合:

$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>

输出除外:

$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()创建的。

【讨论】:

    【解决方案2】:

    XSLT 2.0 允许

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

    当然它也允许

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

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

    【讨论】:

    • 感谢您抽出宝贵时间回答迈克尔!
    【解决方案3】:

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

    当您想排除以某个前缀开头的属性时,您可以使用&lt;xsl:copy-of select="@* except @*[matches(local-name(), '^BadAttyName')]"/&gt;,尽管在这种情况下,已经建议的用&lt;xsl:copy-of select="@*[not(matches(local-name(), '^BadAttyName'))]"/&gt; 否定条件的解决方案可能更紧凑、更容易。

    【讨论】:

    • 感谢马丁的澄清
    猜你喜欢
    • 2013-11-30
    • 1970-01-01
    • 2011-08-24
    • 2019-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    相关资源
    最近更新 更多