如何使用XSLT将属性添加到XML中的根元素?

时间:2010-04-29 04:34:22

标签: xml xslt transformation xslt-2.0

我希望匹配根元素“FOO”并执行转换(添加版本属性),其余部分保持不变。到目前为止我的转型看起来像这样:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://schemas.foo.com/fooNameSpace">

<xsl:template match="//FOO">
    <xsl:choose>
      <xsl:when test="@version">
        <xsl:apply-templates select="node()|@*" />
      </xsl:when>
      <xsl:otherwise>
        <FOO>
         <xsl:attribute name="version">1</xsl:attribute>
         <xsl:apply-templates select="node()|@*" />
        </FOO>
      </xsl:otherwise>
    </xsl:choose>
 </xsl:template>

然而,这不会进行任何转换。它甚至没有检测到元素。所以我需要添加命名空间才能使它工作:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fd="http://schemas.foo.com/fooNameSpace">

 <xsl:template match="//fd:FOO">
 …

但是这会将一个名称空间属性附加到FOO元素以及其他元素:

<FOO xmlns:fd="http://schemas.foo.com/fooNameSpace" version="1" id="fooid">
<BAR xmlns="http://schemas.foo.com/fooNameSpace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  • 有没有办法说该元素正在使用默认命名空间?
  • 我们可以在默认名称空间中匹配和添加元素吗?

以下是原始XML:

  <?xml version="1.0" encoding="UTF-8"?>
  <FOO xmlns="http://schemas.foo.com/fooNameSpace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <BAR>
        <Attribute name="HEIGHT">2067</Attribute>
      </BAR>
  </FOO>

3 个答案:

答案 0 :(得分:1)

您可以通过添加属性xpath-default-namespace来指定XPath表达式的默认命名空间,如XSLT 2.0标准的5.2 Unprefixed QNames in Expressions and Patterns部分所述。

示例:

<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xpath-default-namespace="http://schemas.foo.com/fooNameSpace"> 

    <xsl:template match="FOO[not(@version)]">
        <xsl:copy>
            <xsl:attribute name="version">1</xsl:attribute> 
            <xsl:apply-templates select="node()|@*" /> 
        </xsl:copy>
    </xsl:template>

    <!-- Identity template for copying everything else -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" /> 
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

这适用于我使用xsltproc / libxslt:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="http://schemas.foo.com/fooNameSpace">
  <xsl:template match="/ns:FOO">
    <xsl:copy>
      <xsl:if test="not(@version)">
        <xsl:attribute name="version">1</xsl:attribute>
      </xsl:if>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

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

它产生:

<?xml version="1.0"?>
<FOO xmlns="http://schemas.foo.com/fooNameSpace" version="1">
    <BAR>
        <Attribute>2067</Attribute>
    </BAR>
</FOO>

答案 2 :(得分:0)

这是一个真正符合XSLT精神的解决方案

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fd="http://schemas.foo.com/fooNameSpace"
    >
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/*[self::fd:FOO and not(@version)]">
  <xsl:copy>
    <xsl:attribute name="version">1</xsl:attribute>

    <xsl:call-template name="identity"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时,会生成所需的正确结果

<FOO xmlns="http://schemas.foo.com/fooNameSpace"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 version="1">
   <FOO>
      <BAR>
         <Attribute name="HEIGHT">2067</Attribute>
      </BAR>
   </FOO>
</FOO>