2010-05-04 6 views
1

Je dois fusionner deux documents, ce qui se produit d'une manière que je ne trouve pas dans d'autres exemples. A savoir, qu'il doit correspondre non seulement sur l'attribut d'un nœud à un niveau, mais également sur la valeur d'un attribut à un niveau de nœud inférieur à celui-ci, pour obtenir la valeur de ce nœud.Problème de fusion de fichiers XML similaires avec XSL

Je suis en train de prendre cet exemple:

<?xml version="1.0" encoding="UTF-8" ?> 
<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <marc:record> 
    <marc:datafield tag="035" ind1=" " ind2=" "> 
     <marc:subfield code="a">12345</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="041" ind1=" " ind2=" "> 
     <marc:subfield code="a">eng</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="650" ind1=" " ind2="4"> 
     <marc:subfield code="a">Art</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="949" ind1=" " ind2=" "> 
     <marc:subfield code="i">Review of conference proceedings</marc:subfield> 
    </marc:datafield> 
    </marc:record> 
    <marc:record> 
    <marc:datafield tag="035" ind1=" " ind2=" "> 
     <marc:subfield code="a">54321</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="041" ind1=" " ind2=" "> 
     <marc:subfield code="a">eng</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="650" ind1=" " ind2="4"> 
     <marc:subfield code="a">Byzantine</marc:subfield> 
    </marc:datafield> 
    </marc:record> 
</marc:collection> 

Et quand la valeur de « zone de données » « 035 », « sous-champ » « a » correspond par exemple « 12345 »

<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" 
xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <marc:record> 
    <marc:datafield ind2=" " ind1=" " tag="035"> 
     <marc:subfield code="a">12345</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2="4" ind1=" " tag="650"> 
     <marc:subfield code="a">General works</marc:subfield> 
     <marc:subfield code="x">Historians and critics</marc:subfield> 
     <marc:subfield code="x">Smith, John, 1834-1917</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2="4" ind1=" " tag="650"> 
     <marc:subfield code="a">Généralités</marc:subfield> 
     <marc:subfield code="x">Historiens et critiques d'art</marc:subfield> 
     <marc:subfield code="x">Dietrichson, Lorentz, 1834-1917</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2=" " ind1=" " tag="654"> 
     <marc:subfield code="a">General works</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2=" " ind1=" " tag="654"> 
     <marc:subfield code="a">Généralités</marc:subfield> 
     <marc:subfield code="b">Historiens et critiques d'art</marc:subfield> 
     <marc:subfield code="b">Smith, John, 1834-1917</marc:subfield> 
    </marc:datafield> 
    </marc:record>  
    <marc:record> 
    <marc:datafield ind2=" " ind1=" " tag="035"> 
     <marc:subfield code="a">54321</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2="4" ind1=" " tag="650"> 
     <marc:subfield code="a">General works</marc:subfield> 
     <marc:subfield code="x">Historians and critics</marc:subfield> 
     <marc:subfield code="x">Lange, Julius Henrik, 1838-1896</marc:subfield> 
    </marc:datafield> 
    </marc:record> 
</marc:collection> 

Le résultat devrait être:

<?xml version="1.0" encoding="UTF-8" ?> 
<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <marc:record> 
    <marc:datafield tag="035" ind1=" " ind2=" "> 
     <marc:subfield code="a">12345</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="041" ind1=" " ind2=" "> 
     <marc:subfield code="a">eng</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="650" ind1=" " ind2="4"> 
     <marc:subfield code="a">Art</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2="4" ind1=" " tag="650"> 
     <marc:subfield code="a">General works</marc:subfield> 
     <marc:subfield code="x">Historians and critics</marc:subfield> 
     <marc:subfield code="x">Smith, John, 1834-1917</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2="4" ind1=" " tag="650"> 
     <marc:subfield code="a">Généralités</marc:subfield> 
     <marc:subfield code="x">Historiens et critiques d'art</marc:subfield> 
     <marc:subfield code="x">Dietrichson, Lorentz, 1834-1917</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2=" " ind1=" " tag="654"> 
     <marc:subfield code="a">General works</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2=" " ind1=" " tag="654"> 
     <marc:subfield code="a">Généralités</marc:subfield> 
     <marc:subfield code="b">Historiens et critiques d'art</marc:subfield> 
     <marc:subfield code="b">Smith, John, 1834-1917</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="949" ind1=" " ind2=" "> 
     <marc:subfield code="i">Review of conference proceedings</marc:subfield> 
    </marc:datafield> 
    </marc:record> 
    <marc:record> 
    <marc:datafield tag="035" ind1=" " ind2=" "> 
     <marc:subfield code="a">54321</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="041" ind1=" " ind2=" "> 
     <marc:subfield code="a">eng</marc:subfield> 
    </marc:datafield> 
    <marc:datafield tag="650" ind1=" " ind2="4"> 
     <marc:subfield code="a">Byzantine</marc:subfield> 
    </marc:datafield> 
    <marc:datafield ind2="4" ind1=" " tag="650"> 
     <marc:subfield code="a">General works</marc:subfield> 
     <marc:subfield code="x">Historians and critics</marc:subfield> 
     <marc:subfield code="x">Lange, Julius Henrik, 1838-1896</marc:subfield> 
    </marc:datafield> 
    </marc:record> 
</marc:collection> 

J'ai essayé d'utiliser des exemples que j'ai trouvé qui ont fait des recherches, mais aucun d'entre eux ne semblait fonctionner. Je n'ai inclus aucun de mes XSL, car tous mes résultats étaient désastreux. Je continue à regarder, comme si ça devait être simple, mais je n'obtiens pas de résultats décents. Toute aide ou pointeurs seraient grandement appréciés.

Merci!

Répondre

0

Je pense avoir une réponse pour vous. Ce n'est pas le plus élégant mais ça marche. Fondamentalement, vous exécutez la feuille de style par rapport à l'un des fichiers XML que vous essayez de fusionner, puis vous utilisez la fonction document pour accéder à l'autre fichier XML. Itérer à travers chaque enregistrement dans le premier fichier XML et trouver le point correspondant. Puis itérer à travers le second document et trouver l'enregistrement correspondant et tirez les noeuds appropriés.

<?xml version="1.0" encoding="UTF-8"?> 

<xsl:variable name="doc2" select="document('FourBabyMarcs.xml')"/> 

<xsl:template match="/"> 
    <marc:collection> 
     <xsl:for-each select="marc:collection/marc:record"> 
      <marc:record> 

       <xsl:for-each select="marc:leader"> 
        <xsl:copy-of select="."/> 
       </xsl:for-each> 

       <xsl:for-each select="marc:controlfield"> 
        <xsl:copy-of select="."/> 
       </xsl:for-each> 

       <xsl:for-each select="marc:datafield"> 
        <xsl:copy-of select="."/> 
       </xsl:for-each> 

       <xsl:variable name="ID"> 
        <xsl:value-of select="marc:datafield[@tag='035']/marc:subfield[@code='a']"/> 
       </xsl:variable> 

       <xsl:for-each select="$doc2/*/marc:record"> 
         <xsl:if test="marc:datafield[@tag='035']/marc:subfield[@code='a']=$ID"> 
          <xsl:for-each select="marc:datafield"> 
           <xsl:if test="@tag='650'"> 
            <xsl:copy-of select="."/> 
           </xsl:if> 
           <xsl:if test="@tag='654'"> 
            <xsl:copy-of select="."/> 
           </xsl:if> 
          </xsl:for-each> 
         </xsl:if> 
       </xsl:for-each> 
      </marc:record> 
     </xsl:for-each> 
    </marc:collection> 
</xsl:template> 

0

La solution suivante utilise des clés pour faire des recherches efficaces dans le document fusionné . Il est supposé que tous les éléments datafield à l'exception du datafield correspondant doivent être copiés, et qu'il y aura au plus un datafield correspondant pour chaque record. L'URL du document à fusionner est transmise en tant que paramètre.

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:marc="http://www.loc.gov/MARC21/slim"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:param name="mergeFile"/> 
    <xsl:variable name="mergeDoc" select="document($mergeFile)"/> 

    <xsl:key name="datafield" match="marc:datafield" 
     use="concat(@tag, '|', marc:subfield[@code='a'])"/> 

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

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

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

    <xsl:template match="marc:datafield" mode="merge"> 
     <xsl:variable name="datafieldKey" 
         select="concat(@tag, '|', marc:subfield[@code='a'])"/> 
     <!-- Make the other document the context node with for-each, so that 
      key lookups will consult that document instead of the source 
      document. --> 
     <xsl:for-each select="$mergeDoc"> 
      <xsl:for-each select="key('datafield', $datafieldKey)"> 
       <xsl:copy-of select="preceding-sibling::*"/> 
       <xsl:copy-of select="following-sibling::*"/> 
      </xsl:for-each> 
     </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet>