我正在使用xmlstarlet,它只支持xsl 1.0将一个xml转换为另一个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.
我在哪里弄错了。什么是正确的XSL来获得修改后的XML所需的o / p。
答案 0 :(得分: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>
答案 1 :(得分:1)
只有在没有复制其他节点时,才能向节点添加属性。改变这个:
<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>