2017-04-21 3 views
0

Je suis en train de produire un arbre de données qui ressemble à ceci:1.0 Création html XSL arbre ul-li de XPath, où les données sont dans les attributs XML sous forme de texte délimité par «/»

  • racine
    • 1stGenChild1
      • 2ndGenChild1
      • 2ndGenChild2
    • 1stGenChild2

et ainsi produire le code comme suit:

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

où mes données sont sous la forme:

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

Il serait relativement simple à réaliser cette dans XSLT2 avec tokenise, mais je ne peux pas utiliser XSLT2 pour cela car je suis limité à l'utilisation de MSXML 6.0 uniquement par le système utilisé.

Le plus gros problème que j'ai trouvé est que les méthodes normales de faire ceci ne peuvent pas traiter avec la racine n'étant jamais explicitement énoncée dans son propre attribut, mais j'ai toujours besoin de ce noeud dans la sortie.

Comment puis-je produire un arbre pour les données qui peuvent avoir plus de niveaux de nœud fils? - c'est à dire. beaucoup plus de listes dans les listes que l'exemple ci-dessus.

Est-ce que quelqu'un sait également s'il y a une limite au nombre de listes dans les listes avant que l'indentation ne soit rendue par les navigateurs, car cela rendra la vue inutile.

Merci beaucoup.

+0

« * les méthodes normales de faire cela ne peut pas traiter les données dans un attribut, plutôt qu'à l'intérieur de l'élément. * » Quelle différence est-il? Quelles sont les "méthodes normales" auxquelles vous faites référence? –

+0

À la réflexion, je pense que la différence dans mon cas est que le premier xpath dans mes données n'est pas la racine, c'est le premier enfant. Je veux toujours la même sortie, avec la racine dans son propre niveau. J'ai ajusté la question en conséquence. –

+0

Le nom de l'élément racine est-il connu à l'avance? –

Répondre

1

Voici une méthode simple pour l'imbrication des nœuds en fonction de leur hiérarchie:

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> 

appliquée à votre entrée exemple (après avoir enlevé les @ illégales caractères du nom de l'attribut!), le résultat sera:

<?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> 

Vous n'avez plus qu'à remplacer le:

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

instruction avec un appel à un modèle nommé qui retourne le dernier jeton - voir: https://stackoverflow.com/a/41625340/3016153


Ou faire ceci:

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> 
+0

Très bonnes solutions, mais pas tout à fait la sortie dont j'ai besoin. Comment est-ce que je modifierais ceci pour afficher seulement la dernière partie du chemin dans les éléments child ul, de sorte que la sortie corresponde à ma description? (c'est-à-dire ressemble à une structure de répertoire avec des chemins natifs, plutôt que d'afficher le chemin absolu à chaque niveau) –

+1

N'avez-vous pas lu toute la réponse? –