XSLT:遍历树状结构

Min*_*ras 2 xml xslt tree

我有一个 xml 文档,其中包含类别列表:

<categories>
    <category id="1" parent="0">Configurations</category>
    <category id="11" parent="13">LCD Monitor</category>
    <category id="12" parent="13">CRT Monitor</category>
    <category id="13" parent="1"">Monitors</category>
    <category id="123" parent="122">Printer</category>
    ...
</categories>
Run Code Online (Sandbox Code Playgroud)

以及产品清单:

<products>
  <product>
    ...
   <category>12</category>
    ...
  </product>
    ...
</products>
Run Code Online (Sandbox Code Playgroud)

如果产品的类别等于 12,则应将其转换为“配置/监视器/CRT 监视器”(采用类别 12,然后是其父级 (13),依此类推)。如果parent为0,则停止。

有没有一种优雅的方法可以使用 XSL 转换来做到这一点?

and*_*ncx 5

我不知道这是否会被认为是优雅的,但是有了这个输入:

<root>
    <categories>
        <category id="1" parent="0">Configurations</category>
        <category id="11" parent="13">LCD Monitor</category>
        <category id="12" parent="13">CRT Monitor</category>
        <category id="13" parent="1">Monitors</category>
        <category id="123" parent="122">Printer</category>
    </categories>
    <products>
        <product>
             <category>12</category>
        </product>
        <product>
             <category>11</category>
        </product>
     </products>
</root>
Run Code Online (Sandbox Code Playgroud)

这个 XSLT:

<?xml version="1.0"?>

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

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

<xsl:template match="product">
  <product>
    <path>
      <xsl:call-template name="catwalk">
        <xsl:with-param name="id"><xsl:value-of select="category"/>
        </xsl:with-param>
      </xsl:call-template>
    </path>
  </product>
</xsl:template>

<xsl:template name="catwalk">
  <xsl:param name="id"/>
  <xsl:if test="$id != '0'">
    <xsl:call-template name="catwalk">
      <xsl:with-param name="id"><xsl:value-of select="//category[@id = $id]/@parent"/>
      </xsl:with-param>
    </xsl:call-template>
    <xsl:value-of select="//category[@id = $id]"/><xsl:text>/</xsl:text>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

会给你这个输出:

<?xml version="1.0" encoding="utf-8"?>
  <root>
  <product>
    <path>Configurations/Monitors/CRT Monitor/
    </path>
  </product>
  <product>
     <path>Configurations/Monitors/LCD Monitor/
     </path>
  </product>
  </root>
Run Code Online (Sandbox Code Playgroud)

路径仍然有一个额外的尾部斜杠,您需要另外一点条件 XSLT 来使斜杠仅在您不在第一级时发出。

类别层次结构正确至关重要,否则您的转换很容易陷入无限循环,只有在内存耗尽时才会停止。如果我在真实系统中实现类似的东西,我会很想向 catWalk 模板添加一个参数,该参数在每次调用时都会递增,并将其添加到测试中,这样无论是否找到父级,它都会在 10 次调用后停止循环。