XSLT。如何使用给定名称在最左边的叶子中添加节点?

时间:2010-02-01 07:34:38

标签: xslt

我想在最左边的叶子中添加一个具有给定名称的节点。 例如,

<root>
  <aaa name="a">
    <aaa name="x"/>
  </aaa>
  <aaa name="b">
    <aaa name="y">
      <aaa name="z"/>
    </aaa>
  </aaa>
  <aaa name="c">
    <aaa name="z"/>
  </aaa>
</root>

给定name =“z”并且给定新节点为<aaa name="w">。 新树应该是以下形式:

<root>
  <aaa name="a">
    <aaa name="x"/>
  </aaa>
  <aaa name="b">
    <aaa name="y">
      <aaa name="z">
        <aaa name="w"/>
      </aaa>   
    </aaa>
  </aaa>
  <aaa name="c">
    <aaa name="z"/>
  </aaa>
</root>

5 个答案:

答案 0 :(得分:2)

如果最左边是指具有最大深度的'z'节点,则可以先定义一个变量来计算出最左边的'z'的深度,然后在匹配时添加'w'节点这样一个深度的节点

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <!-- Work out depth of left most 'z' node -->
   <xsl:variable name="LeftMost">
      <xsl:for-each select="//*[@name='z']">
         <xsl:sort select="count(ancestor::*)" order="descending"/>
         <xsl:if test="position() = 1">
            <xsl:value-of select="count(ancestor::*)"/>
         </xsl:if>
      </xsl:for-each>
   </xsl:variable>
   <xsl:template match="/">
      <xsl:apply-templates/>
   </xsl:template>
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
         <xsl:if test="@name='z' and count(ancestor::*) = $LeftMost">
            <aaa name="w"/>
         </xsl:if>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

使用这个,如果你有两个'z'节点在同一深度,你最终会得到一个'w'节点。

另一种方法是使用generate-id()来获取最大深度的第一个'z'的ID,然后在匹配具有相同id的节点时添加'w'。然后,这只会在它找到的最大深度的第一个'z'节点上添加一个'w'节点。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:variable name="LeftMost">
        <xsl:for-each select="//*[@name='z']">
      <xsl:sort select="count(ancestor::*)" order="descending"/>
            <xsl:if test="position() = 1">
                <xsl:value-of select="generate-id()"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>
    <xsl:template match="/">
        <xsl:apply-templates/>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:if test="@name='z' and generate-id() = $LeftMost">
                <aaa name="w"/>
            </xsl:if>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:2)

@Tim C's variable based approach的变体会涉及<xsl:key>和前一轴,如下所示:

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> 
  <xsl:key 
    name="kCountPreceding" match="aaa[@name='z']" 
    use="count(preceding::aaa[@name='z'])"
  />
  <xsl:variable name="vLeftMostId" select="
    generate-id(key('kCountPreceding', 0))" 
  />

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
      <xsl:if test="generate-id() = $vLeftMostId">
        <aaa name="w" />
      </xsl:if>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

这种方法的缺点是,匹配表达式中不允许任何变量。这意味着这不能动态化,密钥的match="aaa[@name='z']"必须是硬编码的。

答案 2 :(得分:0)

你可以从这样的事情开始:

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

  <xsl:template match="/">
    <xsl:apply-templates />
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <xsl:if test="@name='z'">
        <aaa name="w"/>
      </xsl:if>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

答案 3 :(得分:0)

为什么不使用前一轴?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:template match="/">
    <xsl:apply-templates />
  </xsl:template>
  <xsl:template match="*[@name='z' and not(preceding::*[@name='z'])]">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <aaa name="w" />
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="*">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
顺便说一下,最左边的叶子是文件顺序中的第一片叶子,不是吗?

<xsl:for-each select="/descendant::*[@name='z' and not(*)][1]">
  ...
  <aaa name="w" />
  ...
</xsl:for-each>

答案 4 :(得分:0)

  

最左边的叶子是第一片叶子   文件顺序,不是吗?

是的,第一片叶子,名字为