(Optimisation XSLT, code) Comment sortir les noeuds se référant à la valeur des frères et soeurs nœuds ..?

StackOverflow https://stackoverflow.com/questions/2287740

  •  21-09-2019
  •  | 
  •  

Question

Je transformais XML vers XML en utilisant XSLT, L'objectif est de lire la valeur de la balise <node1>, si elle est nulle, alors il doit être affecté à la valeur de <node2>, si encas <node2>, est également null, texte par défaut " Par défaut » doit être affecté à la fois .. balises ..
EDIT: Si <node2>is null et <node1> n'est pas .. alors le code ne doit pas mettre à jour <node2> avec le texte de 'Default' mais il doit être transformé comme il est ..

Ceci est le code XML de test, je suis en train avec:

<root>
    <node1></node1>
    <node2></node2>
  <parent>
    <node1>data1</node1>
    <node2></node2>
  </parent>
  <parent>
    <node1></node1>
    <node2>data2</node2>
  </parent>
  <parent>
    <node1>data1</node1>
    <node2>data2</node2>
  </parent>
</root>

Ce code XSLT j'ai conçu:

   <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
  <xsl:template name="template1" match="node2[(following-sibling::node1[.='']|preceding-sibling::node1[.=''])]">
    <xsl:choose>
      <xsl:when test=".=''">
        <node1><xsl:text>Default</xsl:text></node1>
        <node2><xsl:text>Default</xsl:text></node2>
      </xsl:when>
      <xsl:otherwise>
        <node1>
          <xsl:value-of select="text()"/>
        </node1>
        <xsl:copy>
          <xsl:apply-templates select="node()"/>
        </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="template2" match="node1[.='']"/>

Bien que mon code fonctionne, je ne suis pas satisfait de son bouffant du code .. Y at-il de toute façon de se débarrasser des lignes redondantes (le cas échéant) .... Et est-il une alternative à utiliser 2 modèles pour ce faire ( à savoir template1 et template2), est-il possible de réduire le nombre de modèles?

Était-ce utile?

La solution

I. solution XSLT 1.0:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:variable name="vReplacement">Default</xsl:variable>

       <xsl:variable name="vRep" select=
        "document('')/*/xsl:variable[@name='vReplacement']/text()"/>

     <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
     </xsl:template>

     <xsl:template match="node1[not(node())] | node2[../node1[not(node())]]">
      <xsl:copy>
          <xsl:copy-of select="../node2/text() | $vRep[not(current()/../node2/text())]"/>
      </xsl:copy>
     </xsl:template>
</xsl:stylesheet>

Il est plus court et plus simple que les solutions actuelles -. 7 lignes et moins, Plus important encore, un modèle moins que la solution sélectionnée

Plus important encore , cette solution est tout à fait déclarative et pousser style -. Pas d'appel de modèles nommés et le seul <xsl:apply-templates> est dans la règle d'identité

II. solution XSLT 2.0

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
 </xsl:template>

 <xsl:template match="node1[not(node())] | node2[../node1[not(node())]]">
  <xsl:copy>
      <xsl:sequence select="(../node2/text(), 'Default')[1]"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

En utilisant la puissance de séquences XPath 2.0 cette solution est tout à fait plus courte que la solution XSLT 1.0 .

Quelque chose de semblable est impossible dans XSLT 1.0 (comme la sélection de la première de l'union de deux nœuds sans spécifier prédicats pour faire les deux nœuds mutuellement exclusifs), car le nœud avec le texte par défaut et les node1 / nœuds Node2 appartiennent à des documents et, comme nous le savons bien, la commande de noeud entre les noeuds de différents documents est spécifique de mise en œuvre et n'est pas garantie / prescrit.

Cette solution est tout à fait déclarative (pas si / alors / autre) et complètement pousser style:. Le seul <xsl:apply-templates> est dans la règle d'identité

Autres conseils

<xsl:stylesheet 
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="node1[.=''] | node2[.='']">
    <xsl:copy>
      <xsl:call-template name="GetOwnValue" />
    </xsl:copy>
  </xsl:template>

  <xsl:template name="GetOwnValue">
    <xsl:variable name="node2" select="following-sibling::node2[1]" />
    <xsl:choose>
      <xsl:when test="$node2 != ''">
        <xsl:value-of select="$node2" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>Default</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Je l'ai modifié Tomalak réponse de et accompli l'exigence ..
Comme je l'ai mentionné dans ma question, ce code passe node2 comme nulle (si elle est nulle) si le node1 frères et soeurs n'est pas nulle (et s'il n'y a pas node1 frères et soeurs) ..

Ce code est finalement devenu une alternative à celle que je l'ai écrit dans mon Q .. (je ne dis pas qu'il est assez parfait .. mais je suis heureux que je pourrais essayer .. :-)
Et ce code est plus efficace que le mien par quelques 10-20 .. msecs: -)

Ici, il va ..

  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="node1[.=''] | node2[.='']">
    <xsl:copy>
      <xsl:call-template name="GetOwnValue">
        <xsl:with-param name="node">
          <xsl:value-of select="name()"/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:copy>
  </xsl:template>

  <xsl:template name="GetOwnValue">
    <xsl:param name="node"/>
    <xsl:variable name="node2" select="following-sibling::node2[1]|preceding-sibling::node2[1]" />
    <xsl:variable name="node1" select="following-sibling::node1[1]|preceding-sibling::node1[1]" />
     <xsl:choose>
      <xsl:when test="$node2 != ''">
          <xsl:value-of select="$node2" />
      </xsl:when>
       <xsl:when test="$node!='node1' and ($node1!='' or not(following-sibling::node1[1]|preceding-sibling::node1[1]))"/>
      <xsl:otherwise>
          <xsl:text>Default</xsl:text>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

En utilisant XSLT 2.0 Je le faire, mais le vôtre est plus facile à lire de toute façon.

<xsl:template match="node1[.='']">
    <xsl:copy>
        <xsl:value-of select="if (following-sibling::node2[.!='']) then following-sibling::node2[.!=''] else if (preceding-sibling::node2[.!='']) then preceding-sibling::node2[.!=''] else 'Default'"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="node2[.='']">
    <xsl:copy>
        <xsl:value-of select="if (following-sibling::node1[.!='']) then '' else if (preceding-sibling::node1[.!='']) then '' else 'Default'"/>
    </xsl:copy>
</xsl:template>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top