XSLT: déplacer le noeud d'un niveau vers le haut

je voudrais savoir comment déplacer les noeuds d'un niveau en utilisant XSLT si certaines conditions sont respectées. Pour vous donner un exemple, jetez un coup d'oeil à la source XML suivante:

<Settings>
  <String [...]>
    <Boolean [...]/>
  </String>
</Settings>

C'est le XML que j'ai comme situation de départ. Pour être clair, les noms de noeuds "Settings", "String", "Boolean" sont des noeuds spéciaux que nous avons définis.

le problème est que les noeuds" booléens "ne sont pas autorisés à l'intérieur des noeuds" String". C'est pourquoi je dois déplacer ces noeuds "booléens" au niveau supérieur. Le le XML désiré ressemblerait à ceci:

<Settings>
  <String [...]></String>
  <Boolean [...]/>
</Settings>

le XSLT doit aussi fonctionner avec chaque noeud de chaîne qui a un noeud booléen frère, quelle que soit la position dans L'arborescence XML.

Jusqu'à présent j'ai appris que vous devez d'abord copier tout votre XML en utilisant une "règle d'identité" et ensuite appliquer quelques règles spéciales pour les transformations souhaitées:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"        
  xmlns:fo="http://www.w3.org/1999/XSL/Format" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
  xmlns:fn="http://www.w3.org/2005/xpath-functions">

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

  <!-- special rules ... -->

</xsl:stylesheet>

la chose avec laquelle je suis en difficulté est la règle pour déplacer tous les noeuds "booléens" qui sont des frères de noeuds "String" un monter de niveau. Comment puis-je le faire?!?

8
demandé sur Jens 2011-01-24 11:11:52

3 réponses

Mon interprétation de l'exigence donne la solution

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

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

<xsl:template match="String">
    <xsl:copy>
        <xsl:apply-templates select="child::node()[not(self::Boolean)]"/>
    </xsl:copy>
    <xsl:apply-templates select="Boolean"/>
</xsl:template>

</xsl:stylesheet>
6
répondu Michael Kay 2011-01-24 10:48:40

Essayez le code suivant:

<!-- copy all -->
<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*" />
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>

<!-- ignore booleans-inside-strings -->
<xsl:template match="String/Boolean" />

<!-- place the booleans-inside-strings into the settings element -->
<xsl:template match="Settings">
    <xsl:copy>
        <xsl:copy-of select="//String/Boolean" />
        <xsl:apply-templates />
    </xsl:copy>
</xsl:template>
3
répondu dogbane 2011-01-24 09:00:08

cette solution est assez similaire à celle de @Michae-Kay. Cependant, le dépassement de la règle d'identité est un peu plus précis -- seulement String éléments qui ont vraiment un Boolean enfant sont appariés:

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

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

 <xsl:template match="String[Boolean]">
  <xsl:copy>
    <xsl:apply-templates select="node()[not(self::Boolean)]|@*"/>
  </xsl:copy>
  <xsl:apply-templates select="Boolean"/>
 </xsl:template>
</xsl:stylesheet>

lorsque cette transformation est appliquée au document XML suivant:

<Settings>
    <String>
        <Boolean />
    </String>
    <String/>
</Settings>

le résultat voulu et correct est produit:

<Settings>
   <String/>
   <Boolean/>
   <String/>
</Settings>
3
répondu Dimitre Novatchev 2011-01-24 14:16:29