2010-12-15 54 views
2

J'ai deux fichiers et je souhaite combiner/écraser des nœuds entiers en fonction d'une valeur correspondante particulière dans une arborescence de nœuds.Copie de nœuds entiers basés sur une sous-valeur unique dans XSLT

file1.xml

<record> 
    <key>key1</key> 
    <nodel> 
     <field1>source field1</field1> 
     <field2>source field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
    </record> 

file2.xml

<record> 
    <key>key2</key> 
    <nodel> 
     <field1>match field1</field1> 
     <field2>match field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
    </record> 

sortie souhaitée:

<record> 
    <key>key1</key> 
    <nodel> 
     <field1>source field1</field1> 
     <field2>source field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 

    <nodel> 
     <field1>match field1</field1> 
     <field2>match field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
    </record> 

Alors, je veux vérifier une correspondance dans la searchkey, entre les deux fichiers, et, s'il correspond, copiez le noeud entier de la correspondance dans le fichier de sortie, mais gardez la clé d'origine, pas la correspondance. Je vais ensuite vouloir supprimer le nodel d'origine, mais je suis heureux de le faire comme une transformation ultérieure.

J'ai posé une question similaire récente pour la correspondance sur les nœuds <key>, mais je n'ai pas compris comment la modifier pour obtenir le résultat souhaité.

Merci.

+0

Je suppose qu'en réalité vos fichiers file1.xml et file2.xml contiendront chacun plus d'un enregistrement? Et une structure de nœud au-dessus des enregistrements? Qu'est-ce que tu veux faire avec ça? – TToni

+0

Bonne question, +1. Voir ma réponse pour une solution complète mais courte. :) –

+0

@TToni: oui, il y a quelques centaines d'enregistrements dans chaque fichier, mais je l'ai raccourci par souci de concision. Le seul nœud ci-dessus dans cette instance est la racine, bien que je serais intéressé par une implémentation générique. – debs

Répondre

1

Une solution avec les touches:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kNodeBySearchkey" match="*[searchkey]" use="searchkey"/> 
    <xsl:param name="pSource2" select="'file2.xml'"/> 
    <xsl:variable name="vSource2" select="document($pSource2,/)"/> 
    <xsl:template match="node()|@*" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="*[searchkey]"> 
     <xsl:variable name="vKey" select="searchkey"/> 
     <xsl:call-template name="identity"/> 
     <xsl:for-each select="$vSource2"> 
      <xsl:for-each select="key('kNodeBySearchkey',$vKey)"> 
       <xsl:call-template name="identity"/> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<record> 
    <key>key1</key> 
    <nodel> 
     <field1>source field1</field1> 
     <field2>source field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
    <nodel> 
     <field1>source field1</field1> 
     <field2>source field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
</record> 

Remarque: Je ne veux pas vous conserver l'nodel d'origine, juste Dépouiller la première instruction xsl:call-template.

+0

C'est l'idéal, Alejandro, et merci d'identifier où le premier noeud est copié. Cela vous dérangerait-il d'expliquer ce que veut dire le terme '* [searchkey]? J'ai vu des exemples de correspondances simples, mais je ne comprends pas cette syntaxe. (Je n'ai pas pu savoir ce que signifiait la syntaxe '* [not (self :: type)]' dans l'autre exemple.) – debs

+0

@debs: '* [searchkey]' motif signifie * tout élément ayant au moins un ' searchkey' élément enfant *. '* [not (self :: type)]' signifie * tout élément sauf l'élément 'type' *. –

+0

@Alejandro: merci beaucoup pour cela. Ces types de modèles ne sont pas facilement consultables, donc je n'ai pas réussi à trouver ce qu'ils voulaient dire. Votre aide et vos conseils sont très appréciés. Je note cela comme la réponse car je l'ai trouvé un peu plus facile à suivre, mais ils sont tous les deux bienvenus, et devraient aider à approfondir ma compréhension. – debs

1

Cette transformation:

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

<my:file2> 
    <record> 
    <key>key2</key> 
    <nodel> 
     <field1>match field1</field1> 
     <field2>match field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
    </record> 
</my:file2> 

<xsl:variable name="vFile2" 
     select="document('')/*/my:file2/*"/> 

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

<xsl:template match="/*/*[starts-with(name(),'node')]"> 
    <xsl:call-template name="identity"/> 
    <xsl:apply-templates mode="copy" select= 
    "$vFile2/*[starts-with(name(),'node')] 
        [searchkey=current()/searchkey] 
    "/> 
</xsl:template> 

<xsl:template match="node()" mode="copy"> 
    <xsl:call-template name="identity"/> 
</xsl:template> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur le premier document XML fourni:

<record> 
    <key>key1</key> 
    <nodel> 
     <field1>source field1</field1> 
     <field2>source field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
</record> 

produit le résultat souhaité, correct:

<record> 
    <key>key1</key> 
    <nodel> 
     <field1>source field1</field1> 
     <field2>source field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
    <nodel> 
     <field1>match field1</field1> 
     <field2>match field2</field2> 
     <searchkey>myname</searchkey> 
    </nodel> 
</record> 

Remarque: Le deuxième document XML est représenté en ligne dans la feuille de style - ceci uniquement par commodité. Dans la pratique, il résidera dans son propre fichier et que la définition de $vFile2 sera modifiée:

<xsl:variable name="vFile2" 
     select="document('someFileURIHere')/*"/> 
+0

Merci Dimitre. J'ai essayé cela, et votre code a bien fonctionné, bien que j'aie eu un '' non désiré dans le deuxième noeud. En outre, je l'ai essayé avec le vFile2, mais j'ai eu un débordement de pile, et la sortie était juste le deuxième noeud répété. Je vais essayer de poster mon code au cas où je ferais une erreur. – debs

+0

@debs: Oui, le code fonctionne et je le vérifie toujours avant de publier une solution. L'espace de noms indésirable ne sera pas là lorsque le deuxième document XML est dans son propre fichier. En ce qui concerne le débordement de votre pile, je ne peux pas deviner sans voir le code que vous avez utilisé. –

+0

@debs: J'ai ajouté une petite correction à ma solution - maintenant cela fonctionne avec le deuxième document XML dans un fichier. –

0

tentative à l'entrée du nom de fichier:

xsl

<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:param name="pSource2" select="'file2.xml'"/> 
    <xsl:variable name="vFile2" select="document($pSource2)/*"/> 

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

<xsl:template match="/*/*[starts-with(name(),'node')]"> 
    <xsl:call-template name="identity"/> 
    <xsl:apply-templates select= 
    "$vFile2/*[starts-with(name(),'node')] 
        [searchkey=current()/searchkey] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

donne

<record> 
<key>key1</key> 
<nodel> 
<field1>source field1</field1> 
<field2>source field2</field2> 
<searchkey>myname</searchkey> 
</nodel> 
<nodel> 
<field1>match field1</field1> 
<field2>match field2</field2> 
<searchkey>myname</searchkey> 
</nodel> 

Avec le deuxième noeud répété jusqu'à ce qu'il abandonne.

+0

J'ai ajouté une petite correction à ma solution - maintenant cela fonctionne avec le deuxième document XML dans un fichier. S'il vous plaît, ne spécifiez pas de nouvelles informations comme une réponse - il suffit de modifier votre question. –

+0

ok, fera l'affaire. Merci pour la mise à jour. – debs