Древовидное представление структуры XML - как проверить наличие родителей / предшествующих братьев и сестер внутри рекурсии?

Я пытаюсь представить структуру XML как дерево каталогов. Это редактор навигации, отсюда и названия элементов, ссылки (группа) и ссылка (элемент в группе). Итак, у меня есть разные изображения: i-node, l-node, t-node и e-node изображения (где e пусто, остальные - пунктирные линии). HTML должен быть стандартной таблицей. Каждая ссылка находится в своем новом tr.

Все идет нормально...

пока все хорошо

Но:

вот сделка

В первом случае изображения такие, как ожидалось, но во втором вы видите, где я застрял: как только появляется L-узел (последний элемент на этом уровне), все последующие ссылки должны показывать изображение с пустым узлом для этого уровня. - но вместо этого прямо сейчас есть I-узел. Так что мне нужен совет, как этого добиться. Нужно ли мне проверять XML на предмет его предыдущих братьев и сестер? Или я могу сделать это, передав рекурсивному вызову другой параметр? Любая помощь приветствуется ... Я лучше сделаю это правильно, чем начну исправлять HTML с помощью JS;)

XML:

<navigation>
  <links>
    <link>
       <text>Google</text>
       <links>
         <link>
           <text>Yahoo</text>
         </link>
         <link>
           <text>Amazon</text>
         </link>
       </links>
    </link>
    <link />
    <link />
    <link />
    ...
  </links>
</navigation>

XSL:

<xsl:template match="navigation">
<table>
  <xsl:for-each select="links">
      <xsl:apply-templates select=".">
          <xsl:with-param name="level" select="'1'" />
          <xsl:with-param name="children" select="count(*[links/link])" />
      </xsl:apply-templates>
  </xsl:for-each>
</table>
</xsl:template>

<xsl:template match="links">
    <xsl:param name="level" />
    <xsl:param name="children" />
    <xsl:variable name="count" select="count(link)" />
    <xsl:for-each select="link">
        <tr>
            <xsl:attribute name="class">level<xsl:value-of select="$level" /></xsl:attribute>
            <td>
                <xsl:call-template name="nodeimage.loop">
                    <xsl:with-param name="level" select="$level"></xsl:with-param>
                    <xsl:with-param name="position" select="position()"></xsl:with-param>
                    <xsl:with-param name="count" select="$count" />
                </xsl:call-template>
                <strong><xsl:value-of select="text" /></strong>
            </td>
        </tr>
        <!-- if a link has children... -->
        <xsl:if test="*[link]">
            <xsl:apply-templates select="links">
                <xsl:with-param name="level" select="$level + 1"/>
                <xsl:with-param name="children" select="count(*[link])"/>
            </xsl:apply-templates>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

<xsl:template name="nodeimage.loop">
    <xsl:param name="level"/>
    <xsl:param name="position"/>
    <xsl:param name="count"/>

    <!-- debug this 
    <xsl:value-of select="$position" />of<xsl:value-of select="$count" />, level<xsl:value-of select="$level" />
    -->
    <xsl:if test="$level = 1">
        <xsl:choose>
            <xsl:when test="$position = $count"><!-- last one on same level -->
                <img class="textmiddle" src="/images/backend/l-node.png" />
            </xsl:when>
            <xsl:otherwise>
                <img class="textmiddle" src="/images/backend/t-node.png" />
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
    <xsl:if test="$level &gt; 1">
        <img class="textmiddle" src="/images/backend/i-node.png" />
    </xsl:if>
    <xsl:if test="$level &gt; 1">
        <xsl:call-template name="nodeimage.loop">
            <xsl:with-param name="level">
                <xsl:value-of select="$level - 1"/>
            </xsl:with-param>
            <xsl:with-param name="position">
                <xsl:value-of select="$position"/>
            </xsl:with-param>
            <xsl:with-param name="count">
                <xsl:value-of select="$count"/>
            </xsl:with-param>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

person Erik Pöhler    schedule 11.04.2013    source источник


Ответы (1)


Эти шаблоны (написанные для XSLT 1.0) должны иметь возможность отображать вашу древовидную структуру - они не используют рекурсию, а скорее соответствуют шаблонам для обработки общей структуры, а затем модернизированному шаблону для изображений (путем обработки каждого предка узел контекста):

<xsl:template match="navigation">
    <table>
        <thead>
            <xsl:call-template name="headers" />
        </thead>
        <tbody>
            <xsl:apply-templates select="links" />
        </tbody>
    </table>
</xsl:template>

<xsl:template match="link">
    <xsl:variable name="chain" select="ancestor-or-self::link" />
    <tr class="level{count($chain)}">
        <td>
            <xsl:apply-templates select="$chain" mode="tracks">
                <xsl:with-param name="context" select="." />
            </xsl:apply-templates>
            <strong><xsl:value-of select="text" /></strong>
        </td>
        <td><button>Append new link</button></td>
        <td><xsl:value-of select="url" /></td>
    </tr>
    <xsl:apply-templates select="links" />
</xsl:template>

<xsl:template match="link" mode="tracks">
    <xsl:param name="context" />
    <xsl:variable name="isSame" select="generate-id(.) = generate-id($context)" />
    <xsl:variable name="pos" select="count(preceding-sibling::link)" />
    <xsl:variable name="isLast" select="not(following-sibling::link)" />
    <xsl:variable name="type">
        <xsl:choose>
        <xsl:when test="$isSame">
            <xsl:if test="(following::link or links/link) and not($isLast)">t</xsl:if>
            <xsl:if test="$isLast">l</xsl:if>
        </xsl:when>
        <xsl:when test="$isLast and links/link">e</xsl:when>
        <xsl:when test="following::link and links/link">i</xsl:when>
        <xsl:when test="not(following::link)">e</xsl:when>
    </xsl:choose>
    </xsl:variable>
    <xsl:call-template name="node-type">
        <xsl:with-param name="type" select="$type" />
    </xsl:call-template>
</xsl:template>

<xsl:template name="node-type">
    <xsl:param name="type" select="'t'" />
    <img class="textmiddle" src="/images/backend/{$type}-node.png" />
</xsl:template>

<xsl:template name="headers">
    <tr>
        <th>Link</th>
        <th>&#160;</th>
        <th>URL</th>
    </tr>
</xsl:template>

(Обратите внимание, что при применении шаблонов к узлам links будет использоваться встроенный шаблон для последующей обработки узлов link, если ни один шаблон не соответствует links.)

person greystate    schedule 15.04.2013