xslt根据递归位置重命名节点

时间:2012-09-25 00:32:44

标签: xml xslt

我试图遍历我的XHTML文档中的节点,找到符合一组条件的所有节点子节点,并根据它们相对于它们在文档层次结构中的深度的位置重命名它们。

例如:

我想迭代元素中的节点,并将所有h1,h2,h3,h4,h5或h6转换为h1。

然后我想迭代元素的所有其他子元素,找到名为hN的子节点,并将它们命名为h2。

等等,通过子节点进行无限深度递归,但命名元素达到h6的限制......

这是明确的吗?请原谅,我是xsl的新手。

这是我到目前为止所做的:

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


<xsl:template match="*[contains(@class,'_col')]">
    <xsl:apply-templates select="*" mode="iterate"/>

</xsl:template>



<xsl:template match="*" mode="iterate">

    <xsl:if test="name()='h1' or name()='h2'or name()='h3'or name()='h4'or name()='h5'or name()='h6'">
        <h6>
            <xsl:apply-templates select="@*|node()"/>
        </h6>

    </xsl:if>
    <xsl:if test="name()!='h1' and name()!='h2' and name()!='h3' and name()!='h4' and name()!='h5' and name()!='h6'">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

显然这根本不会起作用 - 如果我可以简单地让工作表输出完整的文档,并将所有h#标签转换为h1标签,那么就不会有h#标签的增量,I&#39 ;感觉还不错。任何人都可以帮忙吗?

感谢。

编辑:

第一个答案是一个很大的帮助,但要明确问题不仅仅是将所有h#标签增加一个,最多六个,它是找到所有h#标签,然后将它们设置为递增的数字,向上至六,取决于他们在doc层次结构中的深度。

这里是xml:

<?xml version="1.0" encoding="UTF-8"?>
<body>
<h2>Theme</h2>
<div class="col _incidental">
    <h2>theme 2</h2>
    <div>
        <h3>theme 3</h3>
        <p>some thext</p>
    </div>
</div>
<div class="col _vital">
    <h2>theme 2</h2>
    <div>
        <h1>theme 3</h1>
        <p>some thext</p>
    </div>
    <h2>theme 2</h2>
    <div>
        <h4>theme 3</h4>
        <p>some thext</p>
        <h3>theme 3</h3>
        <p>some thext</p>
    </div>
</div>
<div class="col _related">
      <h2>theme 2</h2>
      </div>   
          <div>
                <h5>theme 3</h5>
                <p>some thext</p>
          </div>
      </div>
</div>
</body>

输出应该是:

<?xml version="1.0" encoding="UTF-8"?>
<body>
<h1>Theme</h1>
<div class="col _incidental">
    <h2>theme 2</h2>
    <div>
        <h3>theme 3</h3>
        <p>some thext</p>
    </div>
</div>
<div class="col _vital">
    <h2>theme 2</h2>
    <div>
        <h3>theme 3</h3>
        <p>some thext</p>
    </div>
    <h2>theme 2</h2>
    <div>
        <h3>theme 3</h3>
        <p>some thext</p>
        <h3>theme 3</h3>
        <p>some thext</p>
    </div>
</div>
<div class="col _related">
    <h2>theme 2</h2>
    <div>
        <div>
            <h3>theme 3</h3>
            <p>some thext</p>
        </div>
    </div>
</div>
</body>

转换包含hN元素,这些元素根据它们在doc层次结构中的位置编号,相对于找到的最后一个hN。因此,如果我找到一个h2,然后任何兄弟姐妹将被搜索,并且任何hN成为h3,如果没有找到,那么他们的兄弟姐妹会被搜查,然后他们变成h3,然后是兄弟姐妹的任何后代成为h4 ......有道理吗?

1 个答案:

答案 0 :(得分:1)

此转化

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" 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=
 "*[starts-with(name(), 'H')
  and
    substring(name(),2) > 1
  and
    not(substring(name(),2) > 5)
   ]">

   <xsl:element name="h{substring(name(),2)+1}">
      <xsl:copy-of select="namespace::*"/>
     <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
 </xsl:template>
</xsl:stylesheet>

应用于以下XML文档(未提供源XML文档!):

<html>
 <head/>
 <H2> Some H2</H2>

 <div>
   <H3>Some H3</H3>
   <div>
     <H4>Some H4</H4>

     <div>
       <H5>Some H5</H5>
     </div>
   </div>
 </div>
</html>

会产生想要的正确结果:

<html>
   <head/>
   <h3> Some H2</h3>
   <div>
      <h4>Some H3</h4>
      <div>
         <h5>Some H4</h5>
         <div>
            <h6>Some H5</h6>
         </div>
      </div>
   </div>
</html>

<强>解释

  1. 正确使用和覆盖 identity rule

  2. 正确使用模板和匹配模式。

  3. 正确使用标准XPath函数 starts-with() substring()

  4. 正确使用 xsl:element AVT s(属性值模板)。