XSL - 在复制上更新或创建属性

时间:2011-10-04 15:39:11

标签: xml xslt lxml

我有一个XML文档,我想为其生成唯一的ID。某些节点可能已经具有该属性,在这种情况下要替换它。我希望文档中的所有节点都具有该属性。

示例文档将是

<root>
<anode uid='123'/>
<anode/>
</root>

我使用以下样式表

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

    <xsl:template match="*">
        <xsl:copy>
            <xsl:attribute name="uid">
                <xsl:value-of select="generate-id(.)"/>
            </xsl:attribute>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

我得到以下输出。这接近我想要的,但是如何防止将现有ID创建为文本节点?

<root uid="id515559">
<anode uid="id515560">123</anode>
<anode uid="id515562"/>
</root>

我查看了XSLT: How to change an attribute value during <xsl:copy>?,但我无法创建新属性。

如果它有所不同,我正在使用lxml来处理样式表。

3 个答案:

答案 0 :(得分:1)

您需要做的就是添加模板以匹配现有的 uid 属性,并忽略它......

<xsl:template match="@uid" />

所以,使用这个样式表......

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

   <xsl:template match="*">
      <xsl:copy>
         <xsl:attribute name="uid">
            <xsl:value-of select="generate-id(.)"/>
         </xsl:attribute>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="@uid" />
</xsl:stylesheet>

当应用于您的示例XML时,输出如下:

<root uid="IDAEQLT">
   <anode uid="IDA3XLT"></anode>
   <anode uid="IDA0XLT"></anode>
</root>

答案 1 :(得分:0)

Built-in template rule正在通过以下行应用于输入@uid

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

属性的默认模板复制文本,就像您已定义模板一样:

<xsl:template match="text()|@*">
  <xsl:value-of select="."/>
</xsl:template>

为了防止这种情况被应用,请更改apply-templates选择属性,使其不适用于属性,或为任何属性定义新的空白模板,因此:

<xsl:template match="@*" />

您甚至可以更具体,使用类似的模板仅忽略uid属性,因此:

<xsl:template match="@uid" />

答案 2 :(得分:0)

答案并不像添加新匹配来覆盖@uid那样极端。您只需要从select中删除xsl:apply-templates

删除了select的样式表:

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

    <xsl:template match="*">
        <xsl:copy>
            <xsl:attribute name="uid">
                <xsl:value-of select="generate-id(.)"/>
            </xsl:attribute>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

产生以下输出(@uid会有所不同):

<root uid="d0e1">
  <anode uid="d0e3"/>
  <anode uid="d0e5"/>
</root>