2016-12-07 2 views
0

Je voudrais utiliser la liste détaillée des pauses au lieu dur, voir l'exemple:comptage des noeuds précédents renvoie des résultats inattendus

<para>line1<?linebreak?> 
line2<?linebreak?> 
line3</para> 

Cependant, je ressentais un comportement bizarre dans mon modèle récursif qui empêche le traitement de la deuxième ligne correctement. J'ai créé un cas de test simplifié - pas plus récursif. Si l'expression count(preceding::processing-instruction('linebreak')) = 0 est utilisée de cette façon, rien n'est renvoyé, mais je m'attendrais à la deuxième ligne.

<line>line1</line><node> 
line2<?linebreak?> 
line3</node> 
line2 

Cet élément est <node> pour le débogage ici. Cela confirme que je traite les données attendues.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 

    <xsl:template match="para[processing-instruction('linebreak')]"> 
     <xsl:call-template name="getLine"> 
      <xsl:with-param name="node" select="./node()"/> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="getLine"> 
     <xsl:param name="node"/> 

     <line> 
      <xsl:copy-of 
       select="$node/self::processing-instruction('linebreak')[not(preceding::processing-instruction('linebreak'))]/preceding::node()" 
      /> 
     </line> 

     <xsl:call-template name="getSecondLine"> 
      <xsl:with-param name="node" 
       select="$node/self::processing-instruction('linebreak')[not(preceding::processing-instruction('linebreak'))]/following::node()" 
      /> 
     </xsl:call-template> 

    </xsl:template> 

    <xsl:template name="getSecondLine"> 
     <xsl:param name="node"/> 

     <node> 
      <xsl:copy-of select="$node"/> 
     </node> 

     <xsl:copy-of 
      select="$node/self::processing-instruction('linebreak')[count(preceding::processing-instruction('linebreak')) = 0]/preceding::node()" 
     /> 
    </xsl:template> 

</xsl:stylesheet> 

Testé dans Saxon HE/EE 9.6.0.7 (dans Oxygen XML Editor 18).

+0

Indépendamment de votre code XSLT actuel, veuillez fournir la sortie de référence que vous attendez pour votre échantillon d'entrée. – Tomalak

+0

Alors qu'est-ce que vous voulez accomplir? Dans le monde XSLT/XPath 2.0, je considérerais une liste détaillée comme étant simplement une séquence de valeurs, par ex. '('line1', 'line2', 'line3')'.Voulez-vous transformer cet échantillon d'entrée en une séquence de chaînes ou peut-être une séquence d'éléments 'line'? Pourquoi ce paragraphe contient-il des instructions de traitement pour indiquer un saut de ligne ainsi que des sauts de ligne dans le texte? Peut-il y avoir quelque chose de plus complexe que des nœuds de texte en clair et des instructions de traitement '' à l'intérieur d'un élément' para'? –

+0

@MartinHonnen Les lignes sont un contenu mixte, pas un texte brut. J'essaie de copier tous les nœuds avant PI et de passer le reste des nœuds à l'itération suivante. Cependant, ce 'repos' se comporte différemment de la première itération. –

Répondre

2

Le traitement du premier saut de ligne fonctionne correctement:

<line> 
    <xsl:copy-of 
    select="$node/self::processing-instruction('linebreak') 
       [not(preceding::processing-instruction('linebreak'))] 
       /preceding::node()"/> 
</line> 

bien que sur cet échantillon; Sur des données plus complexes, vous obtiendriez des résultats erronés car vous devriez utiliser l'axe preceding-sibling plutôt que l'axe preceding.

Mais le code pourrait être grandement simplifiée, j'écrirait l'expression select comme:

select="$node[self::processing-instruction('linebreak')][1] 
     /preceding-sibling::node()" 

Le traitement du second saut de ligne semble très confus. Vous passez le paramètre

$node/self::processing-instruction('linebreak') 
    [not(preceding::processing-instruction('linebreak'))] 
    /following::node()" 

qui est effectivement

select="$node[self::processing-instruction('linebreak')][1] 
      /following-sibling::node()" 

qui sélectionne les trois noeuds

line2<?linebreak?>line3 

(en plus des espaces) qui vous fournir en sortie au sein d'un élément <node>, produisant

<node>line2<?linebreak?>line3</node> 

(sans tenir compte des espaces à nouveau)

puis vous faire

select="$node/self::processing-instruction('linebreak') 
    [count(preceding::processing-instruction('linebreak'))=0] 
    /preceding::node()" 

Ici $node/self::processing-instruction('linebreak') sélectionne la deuxième de ces trois nœuds, ce qui est la seconde instruction de traitement de retour à la ligne. Le nombre d'instructions de traitement précédentes (ou précédentes) est 1, parce que celui auquel vous avez affaire est le second. Je ne suis pas sûr de ce que vous pensiez, mais je soupçonne que votre erreur est de penser à "précédent" et "suivant" comme sélection par rapport à la position du nœud au sein de la séquence $node, plutôt que par rapport à autres nœuds dans l'arborescence source d'origine. Je recommande de lire la section d'un livre de référence XPath qui décrit les différents axes.

+0

Ma plus grande erreur ici est d'utiliser la barre oblique '$ node/self :: processing-instruction ('linebreak')' au lieu des crochets '$ node [self :: processing-instruction ('linebreak')]' - la raison pour laquelle simple [ 1] n'a pas réussi à sélectionner quoi que ce soit, alors j'ai rendu les choses plus compliquées. –

+0

Je ne comprends toujours pas pourquoi la sélection de $ node [self :: traitement-instruction ('linebreak')] [1]/previous-sibling :: node() 'dans le getSecondLine (modifié en utilisant une proposition de Michael) retourne' line1 line2' quand 'line1' n'apparaît nulle part dans le paramètre' $ node' transmis. –

+1

Parce que $ node est une liste de nœuds, et que ces nœuds ont des frères et sœurs précédents qui ne sont pas dans $ node, et en utilisant l'axe précédent-frère (ou précédent), vous trouvez ces nœuds. –