【问题标题】:While transforming a xml to xml using xsl 1.0. xsl:attribute: Cannot add attributes to an element if children have been already added to the element使用 xsl 1.0 将 xml 转换为 xml 时。 xsl:attribute:如果子元素已添加到元素,则无法将属性添加到元素
【发布时间】:2014-02-24 18:32:18
【问题描述】:

我正在使用仅支持 xsl 1.0 的 xmlstarlet 将一个 xml 转换为另一个。

我正在尝试查找属性“atr1”的值并在同一节点中插入另一个属性“atr2”。

当使用下面的 sample.xml 时

<a>
 <b></b>
 <c>
  <d atr1="#{not MGR_1}" atr2="#{condition1}"></d>
  <d atr1="#{ MGR_2}" ></d>
  <d atr1="2"></d>
 </c>
</a>

用下面的transform.xsl

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

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

<xsl:template match="d[contains(@atr1, 'MGR_')]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>   
<xsl:attribute name="atr2">
<xsl:choose>
  <xsl:when test="@atr2">
   <xsl:value-of select="concat('#{', substring(@atr2,3,string-length(@atr2)-3), ' and not ', substring(@atr1,3))" />            
  </xsl:when>
  <xsl:otherwise>
   <xsl:value-of select="concat('#{not ', substring(@atr1,3))" />
  </xsl:otherwise>
</xsl:choose> 
</xsl:attribute>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

我得到预期的 o/p 如下。

<a>
  <b/>
  <c>
    <d atr1="#{not MGR_1}" atr2="#{condition1 and not not MGR_1}"/>
    <d atr1="#{ MGR_2}" atr2="#{not  MGR_2}"/>
    <d atr1="2"/>
  </c>
</a>

但是当我尝试使用下面的 xml 时。其中有另一个内部元素x,那么问题就来了。

<a>
 <b></b>
 <c>
  <d atr1="#{not MGR_1}" atr2="#{condition1}"></d>
  <d atr1="#{ MGR_2}" ></d>
  <d atr1="2"></d>
  <d atr1="#{ MGR_3}" >
    <x>blah blah blah</x>
  </d>
 </c>
</a>

关于尝试转换上述 XML。我收到一条错误消息

$ xml tr transform.xsl sample.xml
runtime error: file transform.xsl line 14 element attribute
xsl:attribute: Cannot add attributes to an element if children have been already added to the element.

我哪里弄错了。在修改后的 XML 上获得所需 o/p 的正确 XSL 可能是什么。

【问题讨论】:

    标签: xml xslt xmlstarlet


    【解决方案1】:

    您收到的错误消息实际上不言自明。如果子节点已分配给节点,则无法添加属性。

    只需将模板应用于所有属性@* 与将模板应用于所有潜在子节点node() 分开。请注意,这不仅捕获子 元素

    顺便说一句,我只能用 Saxon 9.5.1 重现您的错误消息,但不能用 Saxon 6.5.5 和 Xalan 2.7.1 重现。

    样式表

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
    <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>
    
    <xsl:template match="d[contains(@atr1, 'MGR_')]">
    <xsl:copy>
    <xsl:apply-templates select="@*"/>   
    <xsl:attribute name="atr2">
    <xsl:choose>
      <xsl:when test="@atr2">
       <xsl:value-of select="concat('#{', substring(@atr2,3,string-length(@atr2)-3), ' and not ', substring(@atr1,3))" />            
      </xsl:when>
      <xsl:otherwise>
       <xsl:value-of select="concat('#{not ', substring(@atr1,3))" />
      </xsl:otherwise>
    </xsl:choose> 
    </xsl:attribute>
    <xsl:apply-templates select="node()"/>  
    </xsl:copy>
    </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

      【解决方案2】:

      您只能在没有复制其他节点时向节点添加属性。改变这个:

      <xsl:template match="d[contains(@atr1, 'MGR_')]">
          <xsl:copy>
              <xsl:apply-templates select="@*|node()"/>   
              <xsl:attribute name="atr2">
                  <xsl:choose>
                      <xsl:when test="@atr2">
                          <xsl:value-of select="concat('#{', substring(@atr2,3,string-length(@atr2)-3), ' and not ', substring(@atr1,3))" />            
                      </xsl:when>
                      <xsl:otherwise>
                          <xsl:value-of select="concat('#{not ', substring(@atr1,3))" />
                      </xsl:otherwise>
                  </xsl:choose> 
              </xsl:attribute>
          </xsl:copy>
      </xsl:template>
      

      收件人:

      <xsl:template match="d[contains(@atr1, 'MGR_')]">
          <xsl:copy>
              <xsl:apply-templates select="@*"/>  <!-- changed this -->
              <xsl:attribute name="atr2">
                  <xsl:choose>
                      <xsl:when test="@atr2">
                          <xsl:value-of select="concat('#{', substring(@atr2,3,string-length(@atr2)-3), ' and not ', substring(@atr1,3))" />            
                      </xsl:when>
                      <xsl:otherwise>
                          <xsl:value-of select="concat('#{not ', substring(@atr1,3))" />
                      </xsl:otherwise>
                  </xsl:choose> 
              </xsl:attribute>
              <xsl:apply-templates select="node()"/> <!-- changed this -->
          </xsl:copy>
      </xsl:template>
      

      【讨论】:

      • 您的解决方案很好 - 但是:“您只能在没有复制其他节点时向节点添加属性”并不是真的。我认为您的意思是说不能在 从输入复制子节点或从 XSLT 代码引入子节点之后添加属性。
      猜你喜欢
      • 1970-01-01
      • 2017-10-22
      • 2013-07-19
      • 1970-01-01
      • 2019-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-14
      相关资源
      最近更新 更多