Comment obtenir une sortie XML souhaitée à partir de deux XMLs en utilisant XSLT

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

  •  28-09-2019
  •  | 
  •  

Question

J'utilise XSLT et XML.

La première chose que je vais travailler sur deux xml.

XML d'abord:

<?xml version="1.0"?>
<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682">  
  <tcm:Item ID="tcm:232-564598" Title="010 News Mapping"/>
  <tcm:Item ID="tcm:232-564599" Title="020 CUGOs"/>
  <tcm:Item ID="tcm:232-614307" Title="030 Reserved Urls"/>
</tcm:ListItems>

Second XML nous l'obtenir en utilisant ID ci-dessus à savoir tcm: 232-564598 etc, ci-dessous est l'un des xml pour ID tcm: 232-564598 et d'autres identifiants subirai même type de XML.

<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
  <tcm:Data>
    <tcm:Content>
      <MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F">
        <VanityUrl>
          <old>mbp</old>
          <new>/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
        <VanityUrl>
          <old>about/news</old>
          <new>about/news/news.aspx</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
      </MappingCollection>
    </tcm:Content>
  </tcm:Data>
</tcm:Component>

J'essayant d'obtenir le format ci-dessous XML en utilisant les deux ci-dessus XMLs.

<?xml version="1.0" encoding="UTF-8"?>
<mappings>
    <!-- News mapping -->
    <mapping old="mbp" new="/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f"/>
    <mapping old="about/news" new="about/news/news.aspx"/>
    <!-- CUGO's-->
    <mapping old="/nhs" new="/cugo.aspx?promoCode=UKNHS01&amp;pub=/uk/english"/>
    <mapping old="/hk/ukstudentfare" new="/cugo.aspx?promoCode=HKSTU10&amp;pub=/hk/Chinese"/>
</mappings> 

Voici mon XSLT où je suis en train de le XML généré format ci-dessus, mais il ne fonctionne pas pour moi. S'il vous plaît noter d'abord xml est xml primaire qui sera transformé en utilisant XSLT ci-dessous

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
  <xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>
  <!-- root match-->
  <xsl:template match="tcm:ListItems">
    <mappings>
      <xsl:apply-templates select="tcm:Item"/>
    </mappings>
  </xsl:template>
  <xsl:template match="tcm:Item">
      <xsl:variable name="doc" select="document(@ID)"/>
    <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
      <xsl:comment>
        <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
      </xsl:comment>
    </xsl:if>  
    <xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl">
        <xsl:element name="mapping">
          <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old">
            <xsl:attribute name="old">
              <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new">
            <xsl:attribute name="new">
              <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new"/>
            </xsl:attribute>
          </xsl:if>
          <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded">
            <xsl:attribute name="dateAdded">
              <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded"/>
            </xsl:attribute>
          </xsl:if>
        </xsl:element>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Dans xslt ci-dessus, je suis en mesure d'obtenir la boucle de données va aussi correct, mais les données qui sont été à venir est le même, je boucle moyenne EFFECTUE correcte, mais la valeur du nœud est même

S'il vous plaît Proposez!

Était-ce utile?

La solution

Cette feuille de style:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"
 xmlns:tcm="http://www.tridion.com/ContentManager/5.0"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 exclude-result-prefixes="ns tcm msxsl">
    <xsl:strip-space elements="*"/>
    <xsl:key name="kVanityByComment" match="ns:VanityUrl" use="ns:comments"/>
    <xsl:template match="/">
        <xsl:variable name="vSourcesRTF">
            <xsl:copy-of select="document(tcm:ListItems/tcm:Item/@ID)"/>
        </xsl:variable>
        <mappings>
            <xsl:apply-templates select="msxsl:node-set($vSourcesRTF)/node()"/>
        </mappings>
    </xsl:template>
    <xsl:template match="ns:VanityUrl"/>
    <xsl:template match="ns:VanityUrl[generate-id()=
                                      generate-id(key('kVanityByComment',
                                                      ns:comments)[1])]">
        <xsl:comment>
            <xsl:value-of select="ns:comments"/>
        </xsl:comment>
        <xsl:apply-templates select="key('kVanityByComment',
                                         ns:comments)"
                             mode="output"/>
    </xsl:template>
    <xsl:template match="ns:VanityUrl" mode="output">
        <mapping>
            <xsl:apply-templates/>
        </mapping>
    </xsl:template>
    <xsl:template match="ns:VanityUrl/ns:comments" priority="1"/>
    <xsl:template match="ns:VanityUrl/*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Avec cette entrée:

<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682">
  <tcm:Item ID="229-564598" Title="010 News Mapping"/>
  <tcm:Item ID="229-564598" Title="020 CUGOs"/>
  <tcm:Item ID="229-564598" Title="030 Reserved Urls"/>
</tcm:ListItems>

Et cette source externe URI 229-564598:

<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink">
  <tcm:Data>
    <tcm:Content>
      <MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F">
        <VanityUrl>
          <old>mbp</old>
          <new>/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
        <VanityUrl>
          <old>about/news</old>
          <new>about/news/news.aspx</new>
          <dateAdded>2010-05-03T14:45:00</dateAdded>
          <comments> News mapping </comments>
        </VanityUrl>
      </MappingCollection>
    </tcm:Content>
  </tcm:Data>
</tcm:Component>

Sortie:

<mappings>
    <!-- News mapping -->
    <mapping old="mbp" 
             new="/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f"
             dateAdded="2010-05-03T14:45:00"></mapping>
    <mapping old="about/news"
             new="about/news/news.aspx"
             dateAdded="2010-05-03T14:45:00"></mapping>
</mappings>

EDIT :. Multiples sources d'entrée

Autres conseils

Oui, le changement que vous avez fait est en effet critique. : -)

Qu'est-ce que la boucle for-each n'est sélectionner chaque élément <em:VanityUrl> correspondant à votre expression XPath, faire cet élément le nœud de contexte pour ce qui est à l'intérieur du for-each (appelé template , même si ce n'est pas un <xsl:template> ), puis instancier ce modèle interne avec le nouveau noeud de contexte.

Lorsque vous continuions à utiliser « $ doc / ... » à l'intérieur de la boucle for-each, vous jettes le nœud de contexte, de sorte que le for-each est sans effet (sauf répétition n fois).

Vos relevés de <xsl:if test="$doc/..."> évaluions s'il y avait un tel noeud dans le document entier au lieu de sous le <em:VanityUrl> élément de contexte.

L'instruction <xsl:value-of> accorde une attention seulement le premier nœud du nodeset sélectionné afin que vous obtenez toujours la valeur du premier <em:VanityUrl>, quel que soit le noeud contextuel.

Lorsque vous avez commencé à sélectionner et à tester par rapport au noeud contextuel:

    <xsl:if test="em:old">

tout est devenu meilleur. : -)

Vous avez demandé une contribution précieuse. Pour des raisons de style, vous pouvez remplacer vos tests <xsl:if> avec <xsl:apply-templates>. (Pour une chose que vous allez faire plaisir @Dimitre Novatchev. :-) Donc,

<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
  <xsl:comment>
    <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
  </xsl:comment>
</xsl:if>

devient

<xsl:apply-templates select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments" />

et vous avez besoin d'un modèle séparé pour ceux-ci:

<xsl:template match="em:comments">
  <xsl:comment>
    <xsl:value-of select="."/>
  </xsl:comment>
</xsl:template>

Il y a plusieurs avantages à le faire. Le plus grand est que vous ne devez pas dupliquer cette longue expression XPath, qui était sujette à l'erreur si l'expression jamais besoin d'être modifié. S'il n'y a pas em: éléments de commentaire, l'apply-templates ne rien faire, ne sera donc pas émettre un commentaire

.

Il modularise aussi votre feuille de style, de sorte que vous pouvez modifier la façon dont em: les commentaires sont rendus, séparément où qu'elles se produisent. Cela ne peut pas trop d'importance dans les documents XML simples où em: commentaires se produit en un seul endroit, mais il est le style qui prend le meilleur parti de la puissance de XSLT. Notez également que cette version modifiée Affichera plusieurs commentaires s'il y a plusieurs em: commentaires, que votre version ne sera pas. Encore une fois, vous n'avez probablement pas multiples dans l'entrée, donc il ne peut pas importer.

De même, pour les attributs de sortie:

    <xsl:if test="em:old">
      <xsl:attribute name="old">
        <xsl:value-of select="em:old"/>
      </xsl:attribute>
    </xsl:if>

peut devenir

    <xsl:apply-templates select="em:old[1]" />

avec un modèle distinct

<xsl:template match="em:old">
   <xsl:attribute name="old">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

Notez le [1], ce qui évite la tentative de sortie multiples attributs de old="..." pour le même élément si l'entrée em: VanityUrl a plusieurs em: éléments anciens. Ce serait la cause de votre feuille de style pour soulever une erreur. Mais peut-être vous voulez pour soulever une erreur dans ce cas. Si oui, vous êtes probablement déjà la validation de votre XML d'entrée.

En fait, vous pouvez généraliser ici les apply-templates et le modèle à appliquer à tous les trois attributs:

    <xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]" />

Encore une fois, si l'un de ces éléments ne sont pas présents, rien ne sera fait pour eux (pas d'attribut vide sera produit). Le modèle:

<xsl:template match="em:old | em:new | em:dateAdded">
   <xsl:attribute name="{local-name()}">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

local-name() nous donne le nom de l'élément, sans le préfixe d'espace de noms.

Mise à jour:

Une autre façon de gérer qui serait d'utiliser un mode:

    <xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]"
      mode="make-attribute" />

<xsl:template match="em:*" mode="make-attribute">
   <xsl:attribute name="{local-name()}">
     <xsl:value-of select="."/>
   </xsl:attribute>
</xsl:template>

Ensuite, votre modèle make-attribut peut être utilisé partout, et le motif de correspondance ne doit pas être mis à jour pour correspondre à chaque élément possible, vous voudrez peut-être faire un attribut.

La seule autre chose que je dirais est que l'utilisation des espaces de noms ci-dessus est source de confusion ... il ne devrait pas fonctionner en l'état. Par exemple. votre feuille de style utilise cet URI d'espace pour des éléments tels que VanityURL:

 "http://www.espire.com/tridion/schemas"

mais le second document d'entrée utilise cet espace de noms URI pour les éléments:

 "uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"

Il importe que les préfixes d'espace de noms sont différents ( « em: » par rapport à défaut), mais l'espace de noms URIs doivent correspondre. Je suppose que VanityURI de l'espace de noms URL doit être changé, ou bien votre feuille de style ne fonctionnerait pas ...

HTH!

Vous pouvez essayer aussi !!

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
  <xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>     
  <!-- root match-->
  <xsl:template match="tcm:ListItems">
    <mappings>
      <xsl:apply-templates select="tcm:Item"/>
    </mappings>
  </xsl:template>
  <xsl:template match="tcm:Item">
    <xsl:variable name="doc" select="document(@ID)"/>
    <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments">
      <xsl:comment>
        <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/>
      </xsl:comment>
    </xsl:if>
    <xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl">
      <xsl:element name="mapping">
        <xsl:if test="em:old">
          <xsl:attribute name="old">
            <xsl:value-of select="em:old"/>
          </xsl:attribute>
        </xsl:if>
        <xsl:if test="em:new">
          <xsl:attribute name="new">
            <xsl:value-of select="em:new"/>
          </xsl:attribute>
        </xsl:if>
        <xsl:if test="em:dateAdded">
          <xsl:attribute name="dateAdded">
            <xsl:value-of select="em:dateAdded"/>
          </xsl:attribute>
        </xsl:if>
      </xsl:element>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top