2010-01-20 5 views
1

Quelqu'un peut-il m'aider avec le problème suivant, voici l'entrée XML, le XSLT que j'utilise et la sortie attendue. En fait je sais que c'est parce que generateid n'est pas généré que xslt ne génère pas la sortie désirée, mais je ne sais pas où ce code doit être inséré.XSLT: Conversion d'une structure d'éléments basée sur des valeurs d'attribut

XML:

<item id="N65537" text="catalog"> 
    <item id="N65540" text="cd"> 
    <item id="N65542" text="title"> 
     <item id="N65543" img="VAL" text="Empire Burlesque" /> 
    </item> 
    <item id="N65545" text="artist"> 
     <item id="N65546" img="VAL" text="Bob Dylan" /> 
    </item> 
    <item id="N65548" text="country"> 
     <item id="N65549" text="attr1" img="ATTR"> 
     <item id="N65549_N65549" text="primary" img="ATTRVAL" /> 
     </item> 
     <item id="N65550" img="VAL" text="USA" /> 
    </item> 
    <item id="N65552" text="company"> 
     <item id="N65553" text="attr2" img="ATTR"> 
     <item id="N65553_N65553" text="main" img="ATTRVAL" /> 
     </item> 
     <item id="N65554" img="VAL" text="Columbia" /> 
    </item> 
    <item id="N65556" text="price"> 
     <item id="N65557" img="VAL" text="10.90" /> 
    </item> 
    <item id="N65559" text="year"> 
     <item id="N65560" img="VAL" text="1985" /> 
    </item> 
    </item> 
    <item id="N65563" text="cd"> 
    <item id="N65565" text="title"> 
     <item id="N65566" img="VAL" text="Hide your heart" /> 
    </item> 
    <item id="N65568" text="artist"> 
     <item id="N65569" img="VAL" text="Bonnie Tyler" /> 
    </item> 
    <item id="N65571" text="country"> 
     <item id="N65572" img="VAL" text="UK" /> 
    </item> 
    <item id="N65574" text="company"> 
     <item id="N65575" img="VAL" text="CBS Records" /> 
    </item> 
    <item id="N65577" text="price"> 
     <item id="N65578" img="VAL" text="9.90" /> 
    </item> 
    <item id="N65580" text="year"> 
     <item id="N65581" img="VAL" text="1988" /> 
    </item> 
    </item> 
</item> 

XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:template match="/"> 
    <xsl:call-template name="dispatch"> 
    <xsl:with-param name="nodes" select="node()"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="dispatch"> 
    <xsl:param name="nodes"/> 
    <xsl:choose> 
    <xsl:when test="text()"> 
     <xsl:call-template name="apply" > 
     <xsl:with-param name="select" select="node()" /> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:call-template name="apply" /> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

<xsl:template name="apply"> 
    <xsl:param name="select" select="node()" /> 
    <xsl:for-each select="$select"> 
    <xsl:if test='local-name() !=""'> 
     <xsl:variable name="ename"> 
     <xsl:for-each select="@*"> 
      <xsl:if test='name()="img1"'> 
      <xsl:text><xsl:value-of select="." /></xsl:text> 
      </xsl:if> 
     </xsl:for-each> 
     </xsl:variable> 
     <xsl:variable name="aname"> 
     <xsl:for-each select="@*"> 
      <xsl:if test='name()="img"'> 
      <xsl:text><xsl:value-of select="." /></xsl:text> 
      </xsl:if> 
     </xsl:for-each> 
     </xsl:variable> 

     <xsl:for-each select="@*"> 
     <xsl:variable name="tname"> 
      <xsl:text><xsl:value-of select="." /></xsl:text> 
     </xsl:variable> 
     <xsl:choose> 
      <xsl:when test='name() ="text" and normalize-space($ename) = "VAL" and normalize-space($aname) != "ATTR"'> 
      <xsl:element name="{$tname}"> 
       <xsl:for-each select="$select"> 
       <xsl:call-template name="dispatch"/> 
       </xsl:for-each> 
      </xsl:element> 
      </xsl:when> 
      <xsl:when test='name() ="text" and normalize-space($ename) = "VAL" '> 
      <xsl:value-of select="$tname" /> 
      </xsl:when> 
      <xsl:when test='name() ="text" and normalize-space($aname) = "ATTR"'> 
      <xsl:attribute name="id"><xsl:value-of select="$aname" /></xsl:attribute> 
      </xsl:when> 
     </xsl:choose> 
     </xsl:for-each> 
    </xsl:if> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

Sortie prévue:

<catalog> 
    <cd> 
    <title>Empire Burlesque</title> 
    <artist>Bob Dylan</artist> 
    <country attr1="primary">USA</country> 
    <company attr2="main">Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Hide your heart</title> 
    <artist>Bonnie Tyler</artist> 
    <country>UK</country> 
    <company>CBS Records</company> 
    <price>9.90</price> 
    <year>1988</year> 
    </cd> 
</catalog> 
+1

votre xml fourni n'est pas valide – Scoregraphic

+0

@Scoregraphic - XML ​​_is_ valide. Juste mal structuré. – Oded

+0

Vous devriez probablement considérer la structure xml .. –

Répondre

3

EDIT: réponse modifiée après l'ajout de détails à la question.

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <!-- normal items become an ordinary element --> 
    <xsl:template match="item"> 
    <xsl:element name="{@text}"> 
     <!-- attributes must be created before any other contents --> 
     <xsl:apply-templates select="item[@img='ATTR']" /> 
     <!-- now process sub-elements and values (i.e. "anything else") --> 
     <xsl:apply-templates select="item[not(@img='ATTR')]" /> 
    </xsl:element> 
    </xsl:template> 

    <!-- items with "ATTR" become an attribute --> 
    <xsl:template match="item[@img='ATTR']"> 
    <xsl:attribute name="{@text}"> 
     <xsl:value-of select="item[@img='ATTRVAL']/@text" /> 
    </xsl:attribute> 
    </xsl:template> 

    <!-- items with "VAL" become a simple text --> 
    <xsl:template match="item[@img='VAL']"> 
    <xsl:value-of select="@text" /> 
    </xsl:template> 

</xsl:stylesheet> 

donne

<catalog> 
    <cd> 
    <title>Empire Burlesque</title> 
    <artist>Bob Dylan</artist> 
    <country attr1="primary">USA</country> 
    <company attr2="main">Columbia</company> 
    <price>10.90</price> 
    <year>1985</year> 
    </cd> 
    <cd> 
    <title>Hide your heart</title> 
    <artist>Bonnie Tyler</artist> 
    <country>UK</country> 
    <company>CBS Records</company> 
    <price>9.90</price> 
    <year>1988</year> 
    </cd> 
</catalog> 

La feuille de style fonctionne parce que le processeur XSL choisit des modèles basés sur la spécificité de leurs expressions de correspondance. match="item[@img='ATTR']" est plus spécifique que match="item", donc pour chaque <item> traitées (à travers <xsl:apply-templates select="item" />) le moteur choisit le bon modèle automatiquement.

+0

Merci, ça marche! Pouvez-vous s'il vous plaît m'aider aussi si l'attribut img = "ATTR" valeur devrait être ajouté en tant qu'attribut à l'élément, je modifie mon port d'origine. – user254671

+0

s'il vous plaît aidez-moi avec xml modifié ... – user254671

0

Si vous pouvez modifier le code XML d'entrée, faites-le. XML est censé avoir une signification dans les noms de balises et dans sa structure. Appeler tout item juste le rend illisible. Faire un tel changement vous permettra également d'écrire du XSLT lisible sans recourir aux astuces du sélecteur de la hiérarchie des nœuds.

+0

En fait ce xml est généré par js-treeviewcontrol que j'utilise.so je ne peux pas changer le xml. – user254671

+0

Un contrôle? Donc, ceci est consommé par le contrôle et généré ailleurs? – Oded

+0

L'inputxml que j'ai fourni est généré par le contrôle, maintenant je dois le structurer en fonction de la sortie désirée. – user254671

1

Le problème principal que je vois dans votre solution XSLT est que vous utilisez xsl: if et xsl: choisissez au lieu de 'select' pour filtrer les nœuds. Cela rend votre XSLT difficile à lire et à comprendre (au moins pour moi).

Essayez ceci:

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

    <xsl:template match="/item[@text='catalog']"> 
    <catalog> 
     <xsl:apply-templates select="item[@text='cd']"></xsl:apply-templates> 
    </catalog> 
    </xsl:template> 

    <xsl:template match="item[@text='cd']"> 
    <cd> 
     <title><xsl:value-of select="item[@text='title']/item[@img1='VAL']/@text"/></title> 
     <artist><xsl:value-of select="item[@text='artist']/item[@img1='VAL']/@text"/></artist> 
     <country><xsl:value-of select="item[@text='country']/item[@img1='VAL']/@text"/></country> 
     <company><xsl:value-of select="item[@text='company']/item[@img1='VAL']/@text"/></company> 
     <price><xsl:value-of select="item[@text='price']/item[@img1='VAL']/@text"/></price> 
     <year><xsl:value-of select="item[@text='year']/item[@img1='VAL']/@text"/></year> 
    </cd> 
    </xsl:template> 
</xsl:stylesheet> 

Solution ne couvre pas les nœuds ATTR, car ils ne font pas partie du résultat décrit.

+0

En fait, je suis à la recherche d'une solution générique qui peut être appliquée à n'importe quel XML, où la structure du nœud n'est pas connue à l'avance. – user254671

+0

Vous n'avez pas mentionné votre exigence d'une "solution générique" dans votre question. – devio

+0

xslt doit être indépendant des noms de noeud, par ex. ici catalog/cd/title est utilisé pour obtenir la sortie souhaitée, plutôt si nous appliquons mon xslt où les critères correspondants sont indépendants des noms de nœuds, la sortie générée n'est pas cohérente si le même nom de nœud réapparaît en xml, donc c'est un problème avec id unique , c'est pourquoi son échec, où j'ai besoin de solution. – user254671

0

Que diriez-vous ceci:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
    <xsl:template match="/"> 
     <catalog> 
      <xsl:for-each select="/item[@text='catalog']/item[@text='cd']"> 
       <cd> 
        <xsl:for-each select="item"> 
         <xsl:variable name="ename" select="string(@text)"/> 
         <xsl:variable name="value" select="item/@text"/> 
         <xsl:element name="{$ename}"> 
          <xsl:value-of select="$value"/> 
         </xsl:element> 
        </xsl:for-each> 
       </cd>     
      </xsl:for-each> 
     </catalog> 
    </xsl:template>  
</xsl:stylesheet> 

Pas aussi bien que Tomalaks solution - mais peut-être légèrement plus clair quant à l'intention.

+0

Je ne veux pas que le nom de noeud soit codé en dur à l'intérieur de la solution de xslt.Tomalaks fonctionne très bien, juste j'ai besoin maintenant l'attribut supplémentaire devrait être pris en charge. – user254671

+0

@ cb160: Notez que la question a considérablement changé. – Tomalak

Questions connexes