I have a XML with 5 or 6 levels. All nodes has an unique ID. By this ID, I need to find a specif node and create a list showing only the ancestors of this node. I'll try to explain better with codes:
That's my XML with all options:
<MenuConfig>
<Menu name="name-1" location="location 1" title="Menu 1">
<Item name="name-1.1" location="location 1.1.jsp" title="Menu 1.1"/>
<Item name="name-1.2" location="location 1.2.jsp" title="Menu 1.2"/>
<Item name="name-1.3" location="location 1.3.jsp" title="Menu 1.3">
<Item name="name-1.3.1" location="location 1.3.1.jsp" title="Menu 1.3.1"/>
<Item name="name-1.3.2" location="location 1.3.2.jsp" title="Menu 1.3.2"/>
</Item>
<Item name="name-1.4" location="location 1.4.jsp" title="Menu 1.3">
<Item name="name-1.4.1" location="location 1.4.1.jsp" title="Menu 1.4.1"/>
<Item name="name-1.4.2" location="location 1.4.2.jsp" title="Menu 1.4.2"/>
</Item>
</Menu>
<Menu name="name-2" location="location 2" title="Menu 2">
<Item name="name-2.1" location="location 2.1.jsp" title="Menu 2.1"/>
<Item name="name-2.2" location="location 2.2.jsp" title="Menu 2.2"/>
<Item name="name-2.3" location="location 2.3.jsp" title="Menu 2.3">
<Item name="name-2.3.1" location="location 2.3.1.jsp" title="Menu 2.3.1"/>
<Item name="name-2.3.2" location="location 2.3.2.jsp" title="Menu 2.3.2"/>
</Item>
<Item name="name-2.4" location="location 2.4.jsp" title="Menu 2.3">
<Item name="name-2.4.1" location="location 2.4.1.jsp" title="Menu 2.4.1"/>
<Item name="name-2.4.2" location="location 2.4.2.jsp" title="Menu 2.4.2"/>
</Item>
</Menu>
<Menu name="name-3" location="location 3" title="Menu 3">
<Item name="name-3.1" location="location 3.1.jsp" title="Menu 3.1"/>
<Item name="name-3.2" location="location 3.2.jsp" title="Menu 3.2"/>
<Item name="name-3.3" location="location 3.3.jsp" title="Menu 3.3">
<Item name="name-3.3.1" location="location 3.3.1.jsp" title="Menu 3.3.1"/>
<Item name="name-3.3.2" location="location 3.3.2.jsp" title="Menu 3.3.2"/>
</Item>
<Item name="name-3.4" location="location 3.4.jsp" title="Menu 3.3">
<Item name="name-3.4.1" location="location 3.4.1.jsp" title="Menu 3.4.1">
<Item name="name-3.4.1.1" location="location 3.4.1.1.jsp" title="Menu 3.4.1.1"/>
<Item name="name-3.4.1.2" location="location 3.4.1.2.jsp" title="Menu 3.4.1.2"/>
</Item>
<Item name="name-3.4.2" location="location 3.4.2.jsp" title="Menu 3.4.2">
<Item name="name-3.4.2.1" location="location 3.4.2.1.jsp" title="Menu 3.4.2.1"/>
<Item name="name-3.4.2.2" location="location 3.4.2.2.jsp" title="Menu 3.4.2.2"/>
</Item>
</Item>
</Menu>
</Menu>
</MenuConfig>
That's the XSLT that I'm trying to create:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xalan="http://xml.apache.org/xslt">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="menu"/>
<xsl:template match="/MenuConfig/Menu">
<div id="data-sidebar">
<ul class="sidebar list-unstyled">
<li>
<xsl:attribute name="class">
<xsl:if test="@name = $menu">active</xsl:if>
</xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:value-of select="@title"/>
</xsl:element>
<ul>
<xsl:apply-templates/>
</ul>
</li>
</ul>
</div>
</xsl:template>
<xsl:template match="Item[not(Item)]">
<li>
<xsl:attribute name="class">
<xsl:if test="@name = $menu">active</xsl:if>
</xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:value-of select="@title"/>
</xsl:element>
</li>
</xsl:template>
<xsl:template match="Item[Item]">
<li>
<xsl:attribute name="class">
<xsl:if test="@name = $menu">active</xsl:if>
</xsl:attribute>
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:value-of select="@title"/>
</xsl:element>
<ul>
<xsl:apply-templates select="Item" />
</ul>
</li>
</xsl:template>
</xsl:stylesheet>
I have this external param "menu" where I'll get the current list position (name property)
Let's imagine that the name param is "name-3.4.1.2". In this case, I should show the menu-3 only, the menu-3.4, menu-3.4.1 and children and menu-3.4.2 (sibling of 3.4.1) but without the children. Maybe (it's not confirmed yet by my business manager) I should show only 3 or 4 ancestors levels. Like, if the menu selected is level 6 (1.2.3.4.5.6), I must show up to level 3 (1.2.3) only.
I have no idea how to do it. My real XML is deeper than that and it could be indefinitely deep.
Sorry if I'm not clear enough, but I can't explain better.
Thanks guys...
EDIT: It's the expected output. It's a HTML:
<div id="data-sidebar">
<ul class="sidebar list-unstyled">
<li class=""><a href="location 3.jsp">Menu 3</a>
<ul>
<li class=""><a href="location 3.4.jsp">Menu 3.4</a>
<ul>
<li class=""><a href="location 3.4.1">Menu 3.4.1</a>
<ul>
<li class=""><a href="location 3.4.1.1">Menu 3.4.1.1</a></li>
<li class="active"><a href="location 3.4.1.2">Menu 3.4.1.2</a></li>
</ul>
</li>
<li class=""><a href="location 3.4.2">Menu 3.4.2</a></li>
</ul
</li>
</ul>
</li>
</ul>
</div>
At the browser it should appear like this:
Although this is not exactly simple, I think you are making it much more complicated than it needs to be. Try this as your starting point:
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:param name="name" select="'name-3.4.1.2'"/>
<xsl:template match="*">
<xsl:if test="descendant-or-self::*[@name=$name]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Applied to your example input (corrected for well formedness!) the result is:
<?xml version="1.0" encoding="UTF-8"?>
<MenuConfig>
<Menu name="name-3" location="location 3" title="Menu 3">
<Item name="name-3.4" location="location 3.4.jsp" title="Menu 3.3">
<Item name="name-3.4.1" location="location 3.4.1.jsp" title="Menu 3.4.1">
<Item name="name-3.4.1.2" location="location 3.4.1.2.jsp" title="Menu 3.4.1.2"/>
</Item>
</Item>
</Menu>
</MenuConfig>