复制后更改属性值

时间:2016-01-19 16:05:57

标签: xml xslt xslt-1.0

给出以下XML示例文件:

<root>
    <list number="123">
        <element>
            <name value="Name1"/>
            <line value="Line 1 :"/>
        </element>
        <element>
            <name value="Name1"/>
            <line value="Line 1 :"/>
        </element>
    </list>
</root>

我想创建一个XSL文件,允许我将Line 1 :的每个匹配项替换为Line 1 : 123123来自list节点的属性, number

我有以下XSL文件:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="xml" indent="yes"/>

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

    <xsl:template match="element">
        <xsl:copy-of select="."/>
        <xsl:if test="@value='Line 1 :'">
            <xsl:attribute name="type">
                <xsl:value-of select="root/list[@number]"/>
            </xsl:attribute>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

但是转换失败并返回类似&#34;在已经添加了text,comment,pi或子元素节点之后,属性和命名空间节点无法添加到父元素&#34;。

知道这个XSL有什么问题吗?

1 个答案:

答案 0 :(得分:3)

实际上,您收到错误消息:

  

在添加了text,comment,pi或子元素节点之后,无法将属性和命名空间节点添加到父元素

已经很好地解释了这个问题。与element匹配的模板如下所示

<xsl:template match="element">
    <xsl:copy-of select="."/>
    <xsl:if test="@value='Line 1 :'">
        <xsl:attribute name="type">

里面的第一条指令:

<xsl:copy-of select="."/>

使用其所有内容复制element元素。这包括子元素,文本节点,属性等。

XSLT的规则之一是,一旦将某些类型的节点添加到元素节点,就无法添加更多属性节点。但这正是你想要做的事情

<xsl:attribute name="type">

构造属性节点。

您实际上不需要xsl:copy-of element元素的全部内容,因为您有一个标识模板,默认情况下会复制所有内容。

只干预您想要改变的确切位置。在这种情况下,它是value元素的line属性 - 所以写一个与之完全匹配的模板。

认为您需要的是以下内容。如果没有,请显示您期望的XML输出而不是描述它。我假设可能有多个list元素具有不同的number属性。

XSLT样式表

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="element/line/@value">
        <xsl:attribute name="value">
            <xsl:value-of select="concat(., ' ', ../../../@number)"/>
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

XML输出

<?xml version="1.0" encoding="utf-8"?>
<root>
   <list number="123">
      <element>
         <name value="Name1"/>
         <line value="Line 1 : 123"/>
      </element>
      <element>
         <name value="Name1"/>
         <line value="Line 1 : 123"/>
      </element>
   </list>
</root>

修改

  

更简洁的要求是:给定任何XML文件,如何连接内部的任何属性值等于&#34;第1行:&#34;从上面的数字123?我认为这需要不止一个模板...

不,这只是一个小修改。将第二个模板更改为:

<xsl:template match="list//@*[. = 'Line 1 :']">
    <xsl:attribute name="{name()}">
        <xsl:value-of select="concat(., ' ', ancestor::list[1]/@number)"/>
    </xsl:attribute>
</xsl:template>