Xslt 计算每个节点的Strahler数

Xslt 计算每个节点的Strahler数,xslt,xquery,Xslt,Xquery,节点的长度 在树中是节点高度概念的推广 目标是定义一个转换,该转换向XML文档的每个节点添加一个数字属性,例如strahler 归纳地,节点的Strahler数n,表示为Stn(n),定义如下: 如果n是一片叶子,那么Stn(n)=0 else(n不是叶)通过降低Strahler值对其子项(n1,…,nd)排序:Stn(n1)≥ Stn(n2)≥ ... ≥ Stn(nd)。 如果Stn(n1)=Stn(n2)那么Stn(n)=n1+1;否则Stn(n)=Stn(n1) 例如,对于节点n和

节点的长度 在树中是节点高度概念的推广

目标是定义一个转换,该转换向XML文档的每个节点添加一个数字属性,例如
strahler

归纳地,节点的Strahler数
n
,表示为
Stn(n)
,定义如下:

  • 如果
    n
    是一片叶子,那么
    Stn(n)=0
  • else(
    n
    不是叶)通过降低Strahler值对其子项(
    n1
    ,…,
    nd
    )排序:
    Stn(n1)
    ≥ <代码>Stn(n2)≥ ... ≥
    Stn(nd)
    。 如果
    Stn(n1)=Stn(n2)
    那么
    Stn(n)=n1+1
    ;否则
    Stn(n)=Stn(n1)
例如,对于节点
n
和子节点
n1
n2
n3
和Stn
1
2
3
n
的Stn分别为
3
(因为最大值只出现一次)。对于带有子节点
n1
n2
n3
和Stn
1
2
2
的节点
n
的Stn分别为
3
(因为最大值出现了不止一次)

样本输入

<root field="4">
<a>
    <aa x="1"/>
    <ab>
        <aba number="36" usefulness="useful">
            <abaa>text1</abaa>
            <abab>
                <ababa>text2</ababa>
            </abab>
        </aba>
        <abb number="37" usefulness="useful">
            <abba>text3</abba>
            <abbb>
                <abbba>text4</abbba>
                <abbbb>text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<root strahler="2" field="4">
<a strahler="2">
    <aa strahler="0" x="1"/>
    <ab strahler="2">
        <aba strahler="1" number="36" usefulness="useful">
            <abaa strahler="0">text1</abaa>
            <abab strahler="0">
                <ababa strahler="0">text2</ababa>
            </abab>
        </aba>
        <abb strahler="1" number="37" usefulness="useful">
            <abba strahler="0">text3</abba>
            <abbb strahler="1">
                <abbba strahler="0">text4</abbba>
                <abbbb strahler="0">text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
 xmlns:f="my:f">
 <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="*[true()]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="strahler" select="f:strahler(.)"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:function name="f:strahler" as="xs:integer" saxon:memo-function="yes">
    <xsl:param name="pElem" as="element()"/>

    <xsl:sequence select=
     "if(not($pElem/*))
        then 1
        else 
           if(not($pElem/*[2]))
             then f:strahler($pElem/*[1])
             else for $maxVal in max($pElem/*/f:strahler(.)),
                      $twoWithMax in 
                           (($pElem/*[f:strahler(.) eq $maxVal])[2]/1, 0)[1]
                    return $maxVal+$twoWithMax
     "/>
  </xsl:function>
</xsl:stylesheet>
<root field="4">
    <a>
        <aa x="1"/>
        <ab>
            <aba number="36" usefulness="useful">
                <abaa>text1</abaa>
                <abab>
                    <ababa>text2</ababa>
                </abab>
            </aba>
            <abb number="37" usefulness="useful">
                <abba>text3</abba>
                <abbb>
                    <abbba>text4</abbba>
                    <abbbb>text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
</root>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
    <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="*[true()]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="strahler" select="f:strahler(.)"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="f:strahler" as="xs:integer" cache="full">
        <xsl:param name="pElem" as="element()"/>

        <xsl:sequence select=
         "let $children := $pElem/*
           return
              if(not($children))
                then 1
                else 
                  if(not($children[2]))
                    then f:strahler($children[1])
                    else 
                      let $childrenStrahler := $children/f:strahler(.),
                          $maxVal := max($childrenStrahler),
                          $twoWithMax := ($childrenStrahler[. eq $maxVal][2]!1, 0)[1]
                        return $maxVal +$twoWithMax 
            "/>
    </xsl:function>
</xsl:stylesheet>

文本1
文本2
文本3
文本4
文本5
输出

<root field="4">
<a>
    <aa x="1"/>
    <ab>
        <aba number="36" usefulness="useful">
            <abaa>text1</abaa>
            <abab>
                <ababa>text2</ababa>
            </abab>
        </aba>
        <abb number="37" usefulness="useful">
            <abba>text3</abba>
            <abbb>
                <abbba>text4</abbba>
                <abbbb>text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<root strahler="2" field="4">
<a strahler="2">
    <aa strahler="0" x="1"/>
    <ab strahler="2">
        <aba strahler="1" number="36" usefulness="useful">
            <abaa strahler="0">text1</abaa>
            <abab strahler="0">
                <ababa strahler="0">text2</ababa>
            </abab>
        </aba>
        <abb strahler="1" number="37" usefulness="useful">
            <abba strahler="0">text3</abba>
            <abbb strahler="1">
                <abbba strahler="0">text4</abbba>
                <abbbb strahler="0">text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
 xmlns:f="my:f">
 <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="*[true()]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="strahler" select="f:strahler(.)"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:function name="f:strahler" as="xs:integer" saxon:memo-function="yes">
    <xsl:param name="pElem" as="element()"/>

    <xsl:sequence select=
     "if(not($pElem/*))
        then 1
        else 
           if(not($pElem/*[2]))
             then f:strahler($pElem/*[1])
             else for $maxVal in max($pElem/*/f:strahler(.)),
                      $twoWithMax in 
                           (($pElem/*[f:strahler(.) eq $maxVal])[2]/1, 0)[1]
                    return $maxVal+$twoWithMax
     "/>
  </xsl:function>
</xsl:stylesheet>
<root field="4">
    <a>
        <aa x="1"/>
        <ab>
            <aba number="36" usefulness="useful">
                <abaa>text1</abaa>
                <abab>
                    <ababa>text2</ababa>
                </abab>
            </aba>
            <abb number="37" usefulness="useful">
                <abba>text3</abba>
                <abbb>
                    <abbba>text4</abbba>
                    <abbbb>text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
</root>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
    <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="*[true()]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="strahler" select="f:strahler(.)"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="f:strahler" as="xs:integer" cache="full">
        <xsl:param name="pElem" as="element()"/>

        <xsl:sequence select=
         "let $children := $pElem/*
           return
              if(not($children))
                then 1
                else 
                  if(not($children[2]))
                    then f:strahler($children[1])
                    else 
                      let $childrenStrahler := $children/f:strahler(.),
                          $maxVal := max($childrenStrahler),
                          $twoWithMax := ($childrenStrahler[. eq $maxVal][2]!1, 0)[1]
                        return $maxVal +$twoWithMax 
            "/>
    </xsl:function>
</xsl:stylesheet>

文本1
文本2
文本3
文本4
文本5

XSLT不太可能是实现这一点的最佳工具,主要是因为它无法真正从下至上遍历树。从最深的层次开始,可以一次将Strahler数添加到树的一个层次,但是每次都必须重新处理整个树,这导致了一个非常低效的算法

不过,如果没有其他方法,您可以尝试以下方法:

XSLT2.0

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

<xsl:variable name="max-depth" select="max(//*/count(ancestor::node()))"/>

<xsl:template match="/">
    <xsl:call-template name="strahler">
        <xsl:with-param name="node-set" select="*"/>
        <xsl:with-param name="current-level" select="$max-depth"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="strahler">
    <xsl:param name="node-set" select="*"/>
    <xsl:param name="current-level"/>

    <xsl:variable name="next-set">
        <xsl:apply-templates select="$node-set" mode="strahler">
            <xsl:with-param name="current-level" select="$current-level"/>
        </xsl:apply-templates>
    </xsl:variable>

    <xsl:choose>
        <xsl:when test="$current-level > 1">
            <!-- recursive call -->
            <xsl:call-template name="strahler">
                <xsl:with-param name="node-set" select="$next-set"/>
                <xsl:with-param name="current-level" select="$current-level - 1"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="$next-set"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="*" mode="strahler">
    <xsl:param name="current-level"/>
    <xsl:copy>
        <xsl:if test="count(ancestor::node()) = $current-level">
            <xsl:attribute name="strahler">
                <xsl:variable name="max-strahler" select="max(*/@strahler)" />
                <xsl:choose>
                    <xsl:when test="not(*)">
                        <xsl:value-of select="1"/>
                    </xsl:when>
                    <xsl:when test="count(*[@strahler=$max-strahler]) > 1">
                        <xsl:value-of select="$max-strahler + 1"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$max-strahler"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>
        </xsl:if>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates mode="strahler">
            <xsl:with-param name="current-level" select="$current-level"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

应用于输入示例,结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<root strahler="3" field="4">
   <a strahler="3">
      <aa strahler="1" x="1"/>
      <ab strahler="3">
        <aba strahler="2" number="36" usefulness="useful">
            <abaa strahler="1">text1</abaa>
            <abab strahler="1">
                <ababa strahler="1">text2</ababa>
            </abab>
        </aba>
        <abb strahler="2" number="37" usefulness="useful">
            <abba strahler="1">text3</abba>
            <abbb strahler="2">
                <abbba strahler="1">text4</abbba>
                <abbbb strahler="1">text5</abbbb>
            </abbb>
        </abb>
      </ab>
   </a>
</root>

文本1
文本2
文本3
文本4
文本5
这与您发布的结果不同,但根据您链接到的维基百科文章中的规则,我相信这是正确的


请注意,“高度”在这里没有用处。

这是一个简短而高效的XSLT 2.0转换:

<root field="4">
<a>
    <aa x="1"/>
    <ab>
        <aba number="36" usefulness="useful">
            <abaa>text1</abaa>
            <abab>
                <ababa>text2</ababa>
            </abab>
        </aba>
        <abb number="37" usefulness="useful">
            <abba>text3</abba>
            <abbb>
                <abbba>text4</abbba>
                <abbbb>text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<root strahler="2" field="4">
<a strahler="2">
    <aa strahler="0" x="1"/>
    <ab strahler="2">
        <aba strahler="1" number="36" usefulness="useful">
            <abaa strahler="0">text1</abaa>
            <abab strahler="0">
                <ababa strahler="0">text2</ababa>
            </abab>
        </aba>
        <abb strahler="1" number="37" usefulness="useful">
            <abba strahler="0">text3</abba>
            <abbb strahler="1">
                <abbba strahler="0">text4</abbba>
                <abbbb strahler="0">text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
 xmlns:f="my:f">
 <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="*[true()]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="strahler" select="f:strahler(.)"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:function name="f:strahler" as="xs:integer" saxon:memo-function="yes">
    <xsl:param name="pElem" as="element()"/>

    <xsl:sequence select=
     "if(not($pElem/*))
        then 1
        else 
           if(not($pElem/*[2]))
             then f:strahler($pElem/*[1])
             else for $maxVal in max($pElem/*/f:strahler(.)),
                      $twoWithMax in 
                           (($pElem/*[f:strahler(.) eq $maxVal])[2]/1, 0)[1]
                    return $maxVal+$twoWithMax
     "/>
  </xsl:function>
</xsl:stylesheet>
<root field="4">
    <a>
        <aa x="1"/>
        <ab>
            <aba number="36" usefulness="useful">
                <abaa>text1</abaa>
                <abab>
                    <ababa>text2</ababa>
                </abab>
            </aba>
            <abb number="37" usefulness="useful">
                <abba>text3</abba>
                <abbb>
                    <abbba>text4</abbba>
                    <abbbb>text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
</root>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
    <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="*[true()]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="strahler" select="f:strahler(.)"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="f:strahler" as="xs:integer" cache="full">
        <xsl:param name="pElem" as="element()"/>

        <xsl:sequence select=
         "let $children := $pElem/*
           return
              if(not($children))
                then 1
                else 
                  if(not($children[2]))
                    then f:strahler($children[1])
                    else 
                      let $childrenStrahler := $children/f:strahler(.),
                          $maxVal := max($childrenStrahler),
                          $twoWithMax := ($childrenStrahler[. eq $maxVal][2]!1, 0)[1]
                        return $maxVal +$twoWithMax 
            "/>
    </xsl:function>
</xsl:stylesheet>

使用XSLT 3.0/XPath 3.0实现更紧凑、更高效的解决方案

<root field="4">
<a>
    <aa x="1"/>
    <ab>
        <aba number="36" usefulness="useful">
            <abaa>text1</abaa>
            <abab>
                <ababa>text2</ababa>
            </abab>
        </aba>
        <abb number="37" usefulness="useful">
            <abba>text3</abba>
            <abbb>
                <abbba>text4</abbba>
                <abbbb>text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<root strahler="2" field="4">
<a strahler="2">
    <aa strahler="0" x="1"/>
    <ab strahler="2">
        <aba strahler="1" number="36" usefulness="useful">
            <abaa strahler="0">text1</abaa>
            <abab strahler="0">
                <ababa strahler="0">text2</ababa>
            </abab>
        </aba>
        <abb strahler="1" number="37" usefulness="useful">
            <abba strahler="0">text3</abba>
            <abbb strahler="1">
                <abbba strahler="0">text4</abbba>
                <abbbb strahler="0">text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
 xmlns:f="my:f">
 <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="*[true()]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="strahler" select="f:strahler(.)"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:function name="f:strahler" as="xs:integer" saxon:memo-function="yes">
    <xsl:param name="pElem" as="element()"/>

    <xsl:sequence select=
     "if(not($pElem/*))
        then 1
        else 
           if(not($pElem/*[2]))
             then f:strahler($pElem/*[1])
             else for $maxVal in max($pElem/*/f:strahler(.)),
                      $twoWithMax in 
                           (($pElem/*[f:strahler(.) eq $maxVal])[2]/1, 0)[1]
                    return $maxVal+$twoWithMax
     "/>
  </xsl:function>
</xsl:stylesheet>
<root field="4">
    <a>
        <aa x="1"/>
        <ab>
            <aba number="36" usefulness="useful">
                <abaa>text1</abaa>
                <abab>
                    <ababa>text2</ababa>
                </abab>
            </aba>
            <abb number="37" usefulness="useful">
                <abba>text3</abba>
                <abbb>
                    <abbba>text4</abbba>
                    <abbbb>text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
</root>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
    <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="*[true()]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="strahler" select="f:strahler(.)"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="f:strahler" as="xs:integer" cache="full">
        <xsl:param name="pElem" as="element()"/>

        <xsl:sequence select=
         "let $children := $pElem/*
           return
              if(not($children))
                then 1
                else 
                  if(not($children[2]))
                    then f:strahler($children[1])
                    else 
                      let $childrenStrahler := $children/f:strahler(.),
                          $maxVal := max($childrenStrahler),
                          $twoWithMax := ($childrenStrahler[. eq $maxVal][2]!1, 0)[1]
                        return $maxVal +$twoWithMax 
            "/>
    </xsl:function>
</xsl:stylesheet>


效率

<root field="4">
<a>
    <aa x="1"/>
    <ab>
        <aba number="36" usefulness="useful">
            <abaa>text1</abaa>
            <abab>
                <ababa>text2</ababa>
            </abab>
        </aba>
        <abb number="37" usefulness="useful">
            <abba>text3</abba>
            <abbb>
                <abbba>text4</abbba>
                <abbbb>text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<root strahler="2" field="4">
<a strahler="2">
    <aa strahler="0" x="1"/>
    <ab strahler="2">
        <aba strahler="1" number="36" usefulness="useful">
            <abaa strahler="0">text1</abaa>
            <abab strahler="0">
                <ababa strahler="0">text2</ababa>
            </abab>
        </aba>
        <abb strahler="1" number="37" usefulness="useful">
            <abba strahler="0">text3</abba>
            <abbb strahler="1">
                <abbba strahler="0">text4</abbba>
                <abbbb strahler="0">text5</abbbb>
            </abbb>
        </abb>
    </ab>
</a>
</root>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
 xmlns:f="my:f">
 <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="*[true()]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:attribute name="strahler" select="f:strahler(.)"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:function name="f:strahler" as="xs:integer" saxon:memo-function="yes">
    <xsl:param name="pElem" as="element()"/>

    <xsl:sequence select=
     "if(not($pElem/*))
        then 1
        else 
           if(not($pElem/*[2]))
             then f:strahler($pElem/*[1])
             else for $maxVal in max($pElem/*/f:strahler(.)),
                      $twoWithMax in 
                           (($pElem/*[f:strahler(.) eq $maxVal])[2]/1, 0)[1]
                    return $maxVal+$twoWithMax
     "/>
  </xsl:function>
</xsl:stylesheet>
<root field="4">
    <a>
        <aa x="1"/>
        <ab>
            <aba number="36" usefulness="useful">
                <abaa>text1</abaa>
                <abab>
                    <ababa>text2</ababa>
                </abab>
            </aba>
            <abb number="37" usefulness="useful">
                <abba>text3</abba>
                <abbb>
                    <abbba>text4</abbba>
                    <abbbb>text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
</root>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
    <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="*[true()]">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:attribute name="strahler" select="f:strahler(.)"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>

    <xsl:function name="f:strahler" as="xs:integer" cache="full">
        <xsl:param name="pElem" as="element()"/>

        <xsl:sequence select=
         "let $children := $pElem/*
           return
              if(not($children))
                then 1
                else 
                  if(not($children[2]))
                    then f:strahler($children[1])
                    else 
                      let $childrenStrahler := $children/f:strahler(.),
                          $maxVal := max($childrenStrahler),
                          $twoWithMax := ($childrenStrahler[. eq $maxVal][2]!1, 0)[1]
                        return $maxVal +$twoWithMax 
            "/>
    </xsl:function>
</xsl:stylesheet>

XSLT不太可能是这方面的最佳工具

如果有人告诉你这些,不要相信他们

通过使用记忆功能,两种解决方案都是有效的

事实上,
f:stahler($阳极)
对于每个不同的元素只计算一次

请注意使用:

  • saxon:memo function=“yes”
  • cache=“full”
  • 第一个是其中之一。根据以下文件:

    指定“yes”表示Saxon应该记住 在缓存中调用函数,以及是否再次调用该函数 使用相同的参数,从缓存中检索结果,而不是 而不是重新计算

    第二个是

    <root field="4">
    <a>
        <aa x="1"/>
        <ab>
            <aba number="36" usefulness="useful">
                <abaa>text1</abaa>
                <abab>
                    <ababa>text2</ababa>
                </abab>
            </aba>
            <abb number="37" usefulness="useful">
                <abba>text3</abba>
                <abbb>
                    <abbba>text4</abbba>
                    <abbbb>text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
    </root>
    
    <root strahler="2" field="4">
    <a strahler="2">
        <aa strahler="0" x="1"/>
        <ab strahler="2">
            <aba strahler="1" number="36" usefulness="useful">
                <abaa strahler="0">text1</abaa>
                <abab strahler="0">
                    <ababa strahler="0">text2</ababa>
                </abab>
            </aba>
            <abb strahler="1" number="37" usefulness="useful">
                <abba strahler="0">text3</abba>
                <abbb strahler="1">
                    <abbba strahler="0">text4</abbba>
                    <abbbb strahler="0">text5</abbbb>
                </abbb>
            </abb>
        </ab>
    </a>
    </root>
    
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/"
     xmlns:f="my:f">
     <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="*[true()]">
        <xsl:copy>
          <xsl:apply-templates select="@*"/>
          <xsl:attribute name="strahler" select="f:strahler(.)"/>
          <xsl:apply-templates/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:function name="f:strahler" as="xs:integer" saxon:memo-function="yes">
        <xsl:param name="pElem" as="element()"/>
    
        <xsl:sequence select=
         "if(not($pElem/*))
            then 1
            else 
               if(not($pElem/*[2]))
                 then f:strahler($pElem/*[1])
                 else for $maxVal in max($pElem/*/f:strahler(.)),
                          $twoWithMax in 
                               (($pElem/*[f:strahler(.) eq $maxVal])[2]/1, 0)[1]
                        return $maxVal+$twoWithMax
         "/>
      </xsl:function>
    </xsl:stylesheet>
    
    <root field="4">
        <a>
            <aa x="1"/>
            <ab>
                <aba number="36" usefulness="useful">
                    <abaa>text1</abaa>
                    <abab>
                        <ababa>text2</ababa>
                    </abab>
                </aba>
                <abb number="37" usefulness="useful">
                    <abba>text3</abba>
                    <abbb>
                        <abbba>text4</abbba>
                        <abbbb>text5</abbbb>
                    </abbb>
                </abb>
            </ab>
        </a>
    </root>
    
    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:f="my:f">
        <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="*[true()]">
            <xsl:copy>
                <xsl:apply-templates select="@*"/>
                <xsl:attribute name="strahler" select="f:strahler(.)"/>
                <xsl:apply-templates/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:function name="f:strahler" as="xs:integer" cache="full">
            <xsl:param name="pElem" as="element()"/>
    
            <xsl:sequence select=
             "let $children := $pElem/*
               return
                  if(not($children))
                    then 1
                    else 
                      if(not($children[2]))
                        then f:strahler($children[1])
                        else 
                          let $childrenStrahler := $children/f:strahler(.),
                              $maxVal := max($childrenStrahler),
                              $twoWithMax := ($childrenStrahler[. eq $maxVal][2]!1, 0)[1]
                            return $maxVal +$twoWithMax 
                "/>
        </xsl:function>
    </xsl:stylesheet>
    
    值cache=“full”鼓励处理器保留 在同一转换期间此函数的所有以前调用,以及 尽可能重用此内存中的结果。价值 cache=“partial”鼓励处理器保留此类内存,但 如有必要,丢弃结果以保持内存使用量在 界限。默认值cache=“no”鼓励处理器不要 保留以前通话的记忆


    XSLT很适合这项工作,Dimitre的解决方案非常完美(+1)

    以下是中的替代实现的外观:

    declare function local:strahler($nodes as node()*) as node()*
    {
      for $node in $nodes
      return
        typeswitch ($node)
        case document-node() return
          document {local:strahler($node/node())}
        case element() return
          element {node-name($node)}
          {
            let $children := local:strahler($node/node())
            let $max := (max($children/@strahler), 1)[1]
            return
            (
              $node/@*,
              attribute strahler {$max + (($children/@strahler[. = $max])[2]/1, 0)[1]},
              $children
            )
          }
        default return
          $node
    };
    
    local:strahler(.)
    
    当将其放入文件
    strahler.xq
    ,并在
    sample.xml
    中输入时,可以使用以下命令从命令行运行:

    java net.sf.saxon.Query strahler.xq -s:sample.xml
    

    与XSLT变体一样,它在自下而上添加新属性的同时重写文档。这里的重写比XSLT更明显,但是在本例中XSLT已经足够了。

    我想谦虚地建议重新格式化这个问题,这样您就可以得到正确的回答。据我所知,您询问的内容还不清楚。如果您包含最小的一组示例XML来说明您的问题,再加上所需的输出、当前XSLT代码、当前输出以及您对问题的想法,您就更有可能得到响应。祝你好运。当你说:“n的Stn等于n1+1的Stn”第三个Stn是什么?我把它理解为stn(n)=stn(n+1)^stn(其中^表示“的幂”),但stn不是一个数字,它是一个函数。事实上,我找不到任何关于你的规则的解释