0

我正在尝试生成如下所示的数据树:

    • 第一代儿童1
      • 2ndGenChild1
      • 第二代儿童2
    • 第一代儿童2

因此产生如下代码:

<ul>
  <li>root</li>
  <ul>
    <li>1stGenChild1</li>
  <ul>
    <li>2ndGenChild1</li>
    <li>2ndGenChild2</li>
  </ul>
  <li>1stGenChild2</li>
</ul>

我的数据采用以下形式:

<XML_FILTER>
  <XPATH @xpath="root/1stGenChild1" />
  <XPATH @xpath="root/1stGenChild1/2ndGenChild1" />
  <XPATH @xpath="root/1stGenChild1/2ndGenChild2" />
  <XPATH @xpath="root/1stGenChild2" />
</XML_FILTER>

使用标记化在 XSLT2 中生成它会相对简单,但我不能为此使用 XSLT2,因为我被限制为使用中的系统仅使用 MSXML 6.0。

我发现的最大问题是,执行此操作的常规方法无法处理从未在其自身属性中明确说明的根,但我仍然需要在输出中使用此节点。

如何为可能具有更多子节点级别的数据生成树?- IE。列表中的列表比上面显示的示例多得多。

还有人知道在浏览器不呈现缩进之前列表中的列表数量是否有限制,因为这会使视图无用。

非常感谢。

4

1 回答 1

2

这是根据层次结构嵌套节点的简单方法:

XSLT 1.0

<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:strip-space elements="*"/>

<xsl:template match="/XML_FILTER">
    <ul>
        <xsl:apply-templates select="XPATH[not(contains(@xpath, '/'))]"/>
    </ul>
</xsl:template>

<xsl:template match="XPATH">
    <xsl:variable name="dir" select="concat(@xpath, '/')" />
    <li>
        <xsl:value-of select="@xpath"/>
    </li>   
    <xsl:variable name="child" select="../XPATH[starts-with(@xpath, $dir) and not(contains(substring-after(@xpath, $dir), '/'))]" />
    <xsl:if test="$child">
        <ul>
            <xsl:apply-templates select="$child"/>
        </ul>           
    </xsl:if>
</xsl:template>

</xsl:stylesheet> 

应用于您的示例输入(@从属性名称中删除非法字符后!),结果将是:

<?xml version="1.0" encoding="UTF-8"?>
<ul>
  <li>root</li>
  <ul>
    <li>root/1stGenChild1</li>
    <ul>
      <li>root/1stGenChild1/2ndGenChild1</li>
      <li>root/1stGenChild1/2ndGenChild2</li>
    </ul>
    <li>root/1stGenChild2</li>
  </ul>
</ul>

现在您只需要更换:

<xsl:value-of select="@xpath"/>

调用返回最后一个令牌的命名模板的指令 - 请参阅:https ://stackoverflow.com/a/41625340/3016153


或者改为这样做:

XSLT 1.0

<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:strip-space elements="*"/>

<xsl:template match="/XML_FILTER">
    <ul>
        <xsl:apply-templates select="XPATH[not(contains(@xpath, '/'))]"/>
    </ul>
</xsl:template>

<xsl:template match="XPATH">
    <xsl:param name="parent"/>
    <xsl:variable name="dir" select="concat(@xpath, '/')" />
    <li>
        <xsl:value-of select="substring-after(concat('/', @xpath), concat($parent, '/'))"/>
    </li>   
    <xsl:variable name="child" select="../XPATH[starts-with(@xpath, $dir) and not(contains(substring-after(@xpath, $dir), '/'))]" />
    <xsl:if test="$child">
        <ul>
            <xsl:apply-templates select="$child">
                <xsl:with-param name="parent" select="concat('/', @xpath)"/>
            </xsl:apply-templates>
        </ul>           
    </xsl:if>
</xsl:template>

</xsl:stylesheet> 
于 2017-04-21T16:36:04.107 回答