Mateusz Sarnowski
Mateusz Sarnowski

Reputation: 1

xslt - selecting element with id attribute equals to id other attribute

I'm really new to XML and XSLT. I've read some tutorials and made some simple xsl code. Now I'm struggling with this transformation and it makes me crazy, because I don't have idea how to deal with it.

I've got XML code similar to this:

<navigation >
  <item  id="1" >
    <item  id="6" />
    <item  id="7" >
      <item  id="18" />
      <item  id="19" />
    </item>
    <item  id="8" />
    <item  id="9" />
  </item>
  <item id="2">
    <item  id="10" />
    <item  id="11" />
    <item  id="12" />
  </item>
  <item  id="3"  >
    <item  id="13" />
    <item  id="14" >
      <item  id="20" />
      <item  id="21" />
    </item>
    <item  id="15" />
  </item>
  <item  id="4" >
    <item  id="16" />
    <item  id="17" />
  </item>
  <item  id="5" />
  <current id="7" />
</navigation>

I need to select "item" which currently has the same "id" like "current" id element, and then check it has children - another item elements. If it has, I would like to display children "id" attribute as a nested list, and selected item and its siblings "id" attribute as a first level list. If it has not, I would like to display selected item and its siblings "id" as a nested list, and selected item's parent and parent's siblings as a first level list.

For example, if current id = "7" output will be like this:

- 6
- 7
  - 18
  - 19
- 8
- 9

and for example, if current id = "1" output will be like this:

-1
  -6
  -7
  -8
  -9
-2
-3
-4
-5

Upvotes: 0

Views: 2154

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167436

To find an item element by its id it makes sense to set up a key

<xsl:key name="id" match="item" use="@id"/>

than way we can then use key('id', current/@id) to select the item referenced by the current element.

As for your conditions, it appears that they basically describe the same mapping, only for leaf elements you want to apply the mapping to the parent of that leaf element.

Trying to implement that with XSLT 3 I came up with

  <xsl:key name="id" match="item" use="@id"/>

  <xsl:template match="navigation">
      <ul>
          <xsl:variable name="current-selection" select="key('id', current/@id)"/>
          <xsl:variable name="current-id" select="if ($current-selection[item]) then $current-selection/@id else $current-selection/../@id"/>
          <xsl:apply-templates select="if ($current-selection[item]) then $current-selection/../item else $current-selection/../../item">
              <xsl:with-param name="current-id" select="$current-id" />
          </xsl:apply-templates>
      </ul>
  </xsl:template>

  <xsl:template match="item">
      <xsl:param name="current-id"/>
      <xsl:choose>
          <xsl:when test="@id = $current-id">
              <li>
                  <xsl:value-of select="@id"/>
                  <ul>
                      <xsl:apply-templates/>
                  </ul>
              </li>
          </xsl:when>
          <xsl:otherwise>
              <li>
                  <xsl:value-of select="@id"/>
              </li>
          </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

full example with the various inputs at https://xsltfiddle.liberty-development.net/bFDb2BK/3, https://xsltfiddle.liberty-development.net/bFDb2BK/2, https://xsltfiddle.liberty-development.net/bFDb2BK/1

Upvotes: 1

Related Questions