2010-08-10 2 views
1

J'ai un problème vraiment confus sur mes mains ..résultats XPath de XSLT sont incorrects - ne passe pas par XML entier

Il semble cependant que toute la hiérarchie des données XML ne sont pas recherchée par lors de l'utilisation d'un XPath expression dans XSL.

Certaines données XML mannequin:

<pets name="myPets" NUM="2"> 
    <dog name="allMyDogs" NUM="5"> 
     <dog name="Frank" NUM="3"/> 
     <dog name="Spot" NUM="4"/> 
     <dog name="Rover" NUM="1"/> 
     <dog name="Rupert" NUM="6"/> 
     <cat name="Lucy" NUM="4"/> 
    </dog> 
    <cat name="allMyCats" NUM="4"> 
     <cat name="Simba" NUM="4"/> 
     <cat name="Princess" NUM="5"/> 
     <cat name="Fluffy" NUM="1"/> 
     <cat name="Lucy" NUM="3"/> 
     <cat name="Lucy" NUM="35"/> 
     <cat name="Lucy" NUM="6"/> 
     <cat name="Lucy" NUM="1"/> 
    </cat> 
    <cat name="Lucy" NUM="9"/> 
</pets> 

Ce qui suit est la partie du code XSLT je crois est l'origine du problème:

<xsl:key name="elem_key" match="elem" use="concat(@key, .)" /> 

    <xsl:variable name="all_data"> 
    <xsl:apply-templates select="*"> 
     <xsl:sort select="name()" /> 
    </xsl:apply-templates> 
    </xsl:variable> 

    <xsl:template match="//*[@NUM&lt;=4]"> 
    <elem key="{name()}"> 
     <xsl:copy-of select="@*" /> 
     <xsl:for-each select="@*"> 
     <xsl:sort select="name()" /> 
     <attribute>|<xsl:value-of select="name()" />|</attribute> 
     </xsl:for-each> 
    </elem> 
    </xsl:template> 

    <xsl:template match="/"> 
    <html> 
     <body> 
     <xsl:for-each select="msxsl:node-set($all_data)"> 
       <xsl:for-each select="*[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])]"> 
       <table > 
        <tr> 
        <td>Element Name</td> 
        <xsl:for-each select="*"> 
         <td> 
         <xsl:value-of select="translate(.,'|','')" /> 
         </td> 
        </xsl:for-each> 
        </tr> 
        <xsl:for-each select="key('elem_key', concat(@key, .))"> 
        <xsl:variable name="curr_elem" select="." /> 
        <tr> 
         <td> 
         <xsl:value-of select="@key" /> 
         </td> 
         <xsl:for-each select="*"> 
         <td > 
          <xsl:value-of select="$curr_elem/@*[name()=translate(current(),'|','')]" /> 
         </td> 
         </xsl:for-each> 
        </tr> 
        </xsl:for-each> 
       </table> 
       <p /> 
       </xsl:for-each> 
     </xsl:for-each> 
     </body> 
    </html> 
    </xsl:template> 

L'expression XPath utilisée:

//*[@NUM&lt;=4] 

(Ci-dessus devrait générer beaucoup de résultats)

Les résultats incorrects je reçois:

Element Name name  NUM 
pets   myPets 2 

Comme vous pouvez le voir, il semble arrêter à la racine.

Si je change le XPath à:

//*[@NUM=4] 

Je reçois ces résultats incorrects:

Element Name name NUM 
dog  Spot  4 


Element Name name  NUM 
cat  Lucy  4 


Element Name name  NUM 
cat  allMyCats 4 

Ce qui semble se passer est qu'il arrête la recherche vers le bas dans la hiérarchie une fois qu'il a trouvé une rencontre. Les deux premiers (Spot et Lucy) sont corrects, mais ils s'arrêtent à allMyCats, quand il y a un nœud enfant de allMyCats (Simba) qui a un NUM de 4.

Quelqu'un peut-il m'aider à corriger ce code afin qu'il renvoie les résultats corrects? Je suis assez frustré! :(

Merci!

+0

sans feuille de style complète, je peux seulement deviner ... Si var 'all_data' est déclarée comme élément supérieur d'une feuille de style, alors je suggère d'utiliser un chemin absolu dans' xsl: apply-templates' comme "/ *" –

+0

@ Alejandro: le est le premier élément de la feuille de style, puis le var all_data. J'ai essayé le chemin "/ *" mais cela n'a pas affecté mes résultats. :( – developer

+0

Bonne question (+1) .Voir ma réponse pour l'explication du problème et pour une solution simple. :) –

Répondre

3

changer juste.

<xsl:variable name="all_data"> 
    <xsl:apply-templates select="*"> 
     <xsl:sort select="name()" /> 
    </xsl:apply-templates> 
    </xsl:variable> 

Pour:

<xsl:variable name="all_data"> 
    <xsl:apply-templates select="*/*"> 
     <xsl:sort select="name()" /> 
    </xsl:apply-templates> 
    </xsl:variable> 

La première (de beaucoup) problème est:

<xsl:apply-templates select="*"> 

sélectionne tous les éléments enfants du noeud courant. Le nœud actuel est / et il a un seul enfant - l'élément supérieur pets.

Vous voulez réellement collecter les données pour tous les enfants de pets.

Il y a d'autres problèmes, mais je n'ai pas l'espace et le temps pour les traiter ici.

Le code corrigé complet est ci-dessous:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
version="1.0"> 

<xsl:key name="elem_key" match="elem" 
     use="concat(@key, .)" /> 

    <xsl:variable name="all_data"> 
    <xsl:apply-templates select="*//*"> 
     <xsl:sort select="name()" /> 
    </xsl:apply-templates> 
    </xsl:variable> 

    <xsl:template match="*[@NUM&lt;=4]"> 
    <elem key="{name()}"> 
     <xsl:copy-of select="@*" /> 
     <xsl:for-each select="@*"> 
     <xsl:sort select="name()" /> 
     <attribute>|<xsl:value-of 
      select="concat(name(),'=',.)" />|</attribute> 
     </xsl:for-each> 
    </elem> 
    </xsl:template> 

    <xsl:template match="/"> 
    <html> 
     <body> 
     <xsl:for-each select="msxsl:node-set($all_data)"> 
       <xsl:for-each select= 
       "*[generate-id() 
       = 
        generate-id(key('elem_key',concat(@key, .))[1]) 
       ]"> 
       <table > 
        <tr> 
        <td>Element Name</td> 
        <xsl:for-each select="*"> 
         <td> 
         <xsl:value-of select= 
          "substring-before(translate(.,'|',''),'=')" /> 
         </td> 
        </xsl:for-each> 
        </tr> 
        <tr> 
         <td> 
         <xsl:value-of select="@key" /> 
         </td> 
         <xsl:for-each select="*"> 
         <td> 
          <xsl:value-of select= 
          "substring-after 
           (translate(current(),'|',''), 
           '=' 
           )"/> 
         </td> 
         </xsl:for-each> 
        </tr> 
       </table> 
       <p /> 
       </xsl:for-each> 
     </xsl:for-each> 
     </body> 
    </html> 
    </xsl:template> 
</xsl:stylesheet> 

lorsque cette transformation est appliquée sur le document XML fourni:

<pets name="myPets" NUM="2"> 
    <dog name="allMyDogs" NUM="5"> 
     <dog name="Frank" NUM="3"/> 
     <dog name="Spot" NUM="4"/> 
     <dog name="Rover" NUM="1"/> 
     <dog name="Rupert" NUM="6"/> 
     <cat name="Lucy" NUM="4"/> 
    </dog> 
    <cat name="allMyCats" NUM="4"> 
     <cat name="Simba" NUM="4"/> 
     <cat name="Princess" NUM="5"/> 
     <cat name="Fluffy" NUM="1"/> 
     <cat name="Lucy" NUM="3"/> 
     <cat name="Lucy" NUM="35"/> 
     <cat name="Lucy" NUM="6"/> 
     <cat name="Lucy" NUM="1"/> 
    </cat> 
    <cat name="Lucy" NUM="9"/> 
</pets> 

le résultat recherché (plusieurs animaux) est produit:

<html xmlns:msxsl="urn:schemas-microsoft-com:xslt"> 
    <body> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>cat</td> 
       <td>Lucy</td> 
       <td>4</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>cat</td> 
       <td>allMyCats</td> 
       <td>4</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>cat</td> 
       <td>Simba</td> 
       <td>4</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>cat</td> 
       <td>Fluffy</td> 
       <td>1</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>cat</td> 
       <td>Lucy</td> 
       <td>3</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>cat</td> 
       <td>Lucy</td> 
       <td>1</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>dog</td> 
       <td>Frank</td> 
       <td>3</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>dog</td> 
       <td>Spot</td> 
       <td>4</td> 
      </tr> 
     </table> 
     <p></p> 
     <table> 
      <tr> 
       <td>Element Name</td> 
       <td>name</td> 
       <td>NUM</td> 
      </tr> 
      <tr> 
       <td>dog</td> 
       <td>Rover</td> 
       <td>1</td> 
      </tr> 
     </table> 
     <p></p> 
    </body> 
</html> 
+0

@Dimitre: J'ai essayé ceci avec // * [@ NUM = 4] et // * [@ NUM < = 4] mais je n'ai toujours pas d'enfants sous "allMyCats" – developer

+0

@iHeartGreek: Vous utilisez ensuite un code différent ou un fichier XML. J'ai édité ma réponse et y ai mis la transformation complète, le fichier XML et le résultat. Vous devriez être capable de les copier et de recevoir le même résultat de la transformation. –

+0

@Dimitre: Pour // * [@ NUM < = 4] affiché dans votre code .. Ne m'attendrais-je pas à ce que les chats nommés Fluffy et Simba retournent? Oh et Lucy NUM = 3 et Lucy NUM = 1 manquent aussi à vos résultats. Je suis désolé, mais je n'ai pas reçu les bons résultats avec ce code (copie exacte coller) :(Je suis dans un pétrin – developer

0

*[generate-id()=generate-id(key('elem_key',concat(@key, .))[1])] Vous avez une clé faire une sélection qui correspond à quelques cas, et vous demandez que le premier avec [1]

Je ne suis pas clair sur ce mise en page que vous êtes désireux que les résultats corrects pour conseiller plus