Andre: Elemente vergleichen

Grüßt Euch,

ich habe zwei XML-Dateien. Mit Hilfe eines XSL Stylesheets möchte ich beide Dateien nach Elementen durchsuchen.
Diese Elemente haben eine eindeutige ID als Attribut, die in beiden Dateien vorkommen können.

Beispiel:
Datei 1:

  
[...]  
<Element id=001>  
 Inhalt  
</Element>  
<Element id=002>  
 Inhalt  
</Elment>  
<Element id=003>  
 Inhalt  
</Element>  
[...]  

Datei 2:

  
[...]  
<Element id=001>  
 Inhalt  
</Element>  
<Element id=003>  
 Inhalt  
</Element>  
[...]  

Mir geht es nun darum, beide Dateien auf die gemeinsame ID zu untersuchen und in einer dritten Datei die Ergebnisse darzustellen.

Wäre also für das Beispiel:
Datei 3(Ergebnis):

  
[...]  
<Element id=001>  
 Inhalt (Datei 1)  
 Inhalt (Datei 2)  
</Element>  
<Element id=003>  
 Inhalt (Datei 1)  
 Inhalt (Datei 2)  
</Element>  
[...]  

Der Inhalt von <Element id=002> aus der 1. Datei fällt weg.

Mein Problem ist nun, dass ich nicht weiß, wie ich die Elemente anspreche, so dass der Test durchgeführt wird.
Theoretisch müsste ja jedes Element aus Datei 1 mit allen Elementen aus Datei 2 verglichen werden, dann das 2. Element der Datei 1 mit allen Elementen aus Datei 2 (usw.)

Ein erster, erfolgloser Versuch ergab nicht wirklich einen Test. Hier der Code dazu:

  
[...]  
<xsl:template name="vergleich">  
	<xsl:variable name="Doc_1" select=".//*:featureMember//*:localId[1]"/>  
	<xsl:variable name="Doc_2" select="document('Datei2')//*:localId"/>  
	  
	<xsl:for-each select="$Doc_1">  
			<xsl:choose>  
				<xsl:when test="$Doc_1 = $Doc_2">  
					<xsl:value-of select="$Doc_1"/>  
				</xsl:when>  
			</xsl:choose>  
	</xsl:for-each>  
</xsl:template>  

Als Ergebnis erhalte ich die Ausgabe aller Elemente der beiden Dateien so oft, wie Elemente enthalten sind (heißt also, die Schleife wird bei 20 Elementen 20 mal durchlaufen).
Der Test scheint nicht zu funktionieren, ein Vergleich "$Doc_1 != $Doc_2" ergab das gleiche Ergebnis.

Weiß jemand einen Ansatz
Vielen Dank und viele Grüße

Frutz

  1. Hm,

    also deine Abfragen laufen ziemlich ins leere.

    Generell kann du so vorgehen (code nicht getested!):

      
    <xsl:template name="vergleich">  
     <xsl:variable name="Doc_1" select=".//*:featureMember//*:localId[1]"/>  
     <xsl:variable name="Doc_2" select="document('Datei2')//*:localId"/>  
      
      <!-- for each nur auf elemente mit id attribute anwenden -->  
     <xsl:for-each select="$Doc_1[@id]">  
       <!-- teste ob id in Doc_2 existiert -->  
       <xsl:if test="$Doc_2[@id = current()/@id]">  
           <!-- gib element aus -->  
          <xsl:element name="{name()}">  
             <xsl:attribute name="id">  
                <xsl:value-of select="current()/@id"/>  
             </xsl:attribute>  
             <!-- inhalt von doc_1 element -->  
                  <xsl:value-of select="current()"/>  
             <!-- inhalt von doc_2 element -->  
                  <xsl:value-of select="$Doc_2[@id = current()/@id]"/>  
          </xsl:element>  
     </xsl:if>  
     </xsl:for-each>  
    </xsl:template>  
      
      
    
    
    1. Hallo Holger,

      vielen Dank, das hat schon sehr geholfen. Ich bin jetzt so weit, dass er die richtigen Knoten anspricht, also die Knoten, die nicht in beiden Dokumenten vorhanden sind, gibt es auch im Ergebnisdokument nicht mehr.

      Dafür hab ich jetzt noch ein zweites Problem.

      Und zwar kopiert er mir entweder nur die ID's.

      <xsl:copy-of select="$Doc_2[@*:id = current()/@*:id]//*:featureMember"/>

      oder er kopiert mir den gesamten Inhalt der zweiten Datei in jedes Element der ersten Datei immer wieder. (Das habe ich hier so erwartet)

      <xsl:copy-of select="document('Pillnitz_Tempo_OK.gml')//*:featureMember"/>

      Mir ist klar, dass er im 2. Beispiel die 2. Datei komplett durchläuft und kopiert. Meine Frage ist nun, ob es sozusagen ein Zwischending gibt. Dass heißt, dass aus der zweiten Datei alle Elemente und Kind-Elemente eines <featureMember>-Containers auch nur einmal kopiert werden (die Position ist dabei egal, d. h., die Elemente der 2. Datei können auch ruhig erst am Ende der Elemente der ersten Datei stehen)

      Zur Verdeutlichung noch einmal ein <featureMember>-Container aus den Originaldaten

        
      <gml:featureMember>  
      		<TN-RO:RoadLink gml:id="DE.DS_PILLNITZ.X00VG6V002">  
      			<NET:beginLifespanVersion>2010-05-05T18:30:00.000</NET:beginLifespanVersion>  
      			<NET:inspireId>  
      				<BASE:Identifier>  
      					<BASE:localId>X00VG6V002</BASE:localId>  
      					<BASE:namespace>DE.DS_PILLNITZ</BASE:namespace>  
      				</BASE:Identifier>  
      			</NET:inspireId>  
      			<NET:endLifespanVersion xsi:nil="true" nilReason="unknown"/>  
      			<NET:inNetwork xsi:nil="true" nilReason="inapplicable"/>  
      			<NET:centrelineGeometry>  
      				<gml:LineString gml:id="X00VG6V002_L" srsDimension="2">  
      					<gml:posList>421517.138161 5654848.606799 421528.613396 5654825.026112 421538.109440 5654804.014417 421540.048629 5654799.406239 </gml:posList>  
      				</gml:LineString>  
      			</NET:centrelineGeometry>  
      			<NET:fictitious>true</NET:fictitious>  
      			<TN:validFrom>2010-05-05T18:30:00.000</TN:validFrom>  
      			<TN:validTo xsi:nil="true" nilReason="unknown"/>  
      		</TN-RO:RoadLink>  
      	</gml:featureMember>  
      
      

      Schau natürlich selbst weiter, aber falls Du(oder jemand anders) ne Lösung hat, wär ich nicht böse;)

      Danke,
      Gruß,
      André

      1. Sorry,

        aber ich verstehe nicht so ganz was du erreichen moechtest. Du solltest dir etwas genauer XPATH Anweisungen anschauen. Ebenso von Vorteil ist das ausschreiben der XPATH Notation. Hier noch ein Vorschlag wie du es machen kannst.

        <xsl:for-each select="//*[@*:id]">
         <xsl:variable name="idVonDoc_1" select="@*:id"/>

        <!-- bis hierhin kontext ist doc 1 -->

        <xsl:for-each select="document('Pillnitz_Tempo_OK.gml')//*[@*:id = $idVonDoc_1]">
          <!-- jetzt hat der kontext gewechselt und du navigierst im kontext von doc_2 -->

        <!-- kopiere alle childs vom ersten uebergeordneten featureMember von doc_2 -->

        <xsl:copy-of select="ancestor::*:featureMember[1]/*"/>

        </xsl:for-each>

        Gruss, Holge r
        <!-- jetzt ist wieder der kontext von doc_1 gueltig -->

        </xsl:for-each>

        Beachte immer in welchem Kontext du dich mit den XPATH Anweisungen bewegst
        Wie gesagt, deine XPATH Anweisungen sollten immer sehr genau sein, ansosnten geht das zu Lasten der Performance. Zu den XPath Anweisungen gibt es eine gute Anleitung hier:

        http://de.selfhtml.org/xml/darstellung/xpathsyntax.htm#knotentypen_achsen_pfade

        1. Hallo Holger,

          ich habe es hinbekommen, vielen Dank.

          Falls es Dich interessiert, um was es geht.
          Ich habe zwei WFS (ist ein Begriff?). Der Nutzer kann innerhalb eines WFS Filter-Abfragen absetzen. Als Ergebnis erhält er 2 GML-Dateien.

          In beiden Dateien haben identische Objekte der Realwelt, gleiche ID's, führen aber unterschiedliche Informationen. GML 1 unter anderem die Geometrie, GML 2 zusätzliche andere Informationen.

          Und nun möchte ich - je nach Nutzerabfrage - eine Gesamt-GML aus den beiden Einzel-GML's erhalten, dabei sollen aber nur die Elemente erhalten bleiben, die in beiden GML Informationen haben.

          Soviel dazu.

          Dank Dir noch mal, auch für den Link.

          Gruß,
          André

          1. Du solltest dir ueberlegen,

            in welchen Rahmen du arbeitest und ob Alternativen verfuegbar sind. XSLT ist nicht immer die beste Wahl wenn es darum geht, XML auszuwerten. Insbesondere ist es ziemlich langsam wenn man nihct entsprechende stylesheets im speicher vorhaelt. Gerade die Aufgabe, die du beschreibst, klingt stark nach komplexeren Navigieren ueber XML Knoten, hier ist insbesondere der Einsatz von DOM oft nuetzlich. XSLT ist immer dann ideal, wenn man alles in einem "Rutsch" parsen kann ohne viele (globale) Variablen anzulegen.

            Gruss, Holge r