Alex: Elemente referenzieren auf weitere XML Dokumente

Hallo Community,

ich hoffe die Experten können mir helfen, ich glaube es ist ein ganz schön verzwicktes Problem.
Gegeben ist ein Quell-XML, in dem es Elemente geben kann das weitere XMLs adressiert, in der Form:

<Widget Name="PremiumCombiView_Audio_CD" FileNamePrefix="PremiumCombiView_Audio_CD" UniqueID="126551782039362000" Path="Container">

Sprich das XML liegt unter dem Pfad
Container/PremiumCombiView_Audio_CD.xml
als Eigenschaft haben alle XML eine UniqueID.

Das wäre an sich kein Problem mit einem rekursiven Template
zu realiseren, das Problem ist das sich ja mehrere Widget
Elemente in einem Dokument befinden können und ich immer nur
das erste Element finde, in das nächste Dokument wechsele und wieder
nach Widget Elementen suche. Wie ihr euch vorstellen könnt, kann sich das zu einer weiten Verzweigung führen.
Folgende "Skizze" soll das Problem verdeutlichen.

XML1  |   XML2   |   XML3   |  XMLx         Ebene

Widget--->Widget--->Widget                   (1)
       |         |->Widget-->Widget          (2)
       |
       |->Widget------------>Widget          (3)

Wie ist es möglich in alle referenzierten XMLs zu wechseln ?
Sollte ich zuerst alle Widgets in Ebene 1 abarbeiten, dann Ebene 2,
aber wie kann ich das anstellen ich verliere doch den Kontext wenn ich von einem XML ins nächste wechsele ?

Ich hoffe das Problem ist klar, wenn nicht kann ich es noch weiter ausführen.
Ich danke euch schon im Vorraus für eure Antworten....

Grüße Alex

  1. Hallo,

    ich hoffe die Experten können mir helfen, ich glaube es ist ein ganz schön verzwicktes Problem.
    Gegeben ist ein Quell-XML, in dem es Elemente geben kann das weitere XMLs adressiert, in der Form:

    <Widget Name="PremiumCombiView_Audio_CD" FileNamePrefix="PremiumCombiView_Audio_CD" UniqueID="126551782039362000" Path="Container">

    Sprich das XML liegt unter dem Pfad
    Container/PremiumCombiView_Audio_CD.xml
    als Eigenschaft haben alle XML eine UniqueID.

    Das wäre an sich kein Problem mit einem rekursiven Template
    zu realiseren, das Problem ist das sich ja mehrere Widget
    Elemente in einem Dokument befinden können und ich immer nur
    das erste Element finde, in das nächste Dokument wechsele und wieder
    nach Widget Elementen suche. Wie ihr euch vorstellen könnt, kann sich das zu einer weiten Verzweigung führen.
    Folgende "Skizze" soll das Problem verdeutlichen.

    XML1  |   XML2   |   XML3   |  XMLx         Ebene

    Widget--->Widget--->Widget                   (1)
           |         |->Widget-->Widget          (2)
           |
           |->Widget------------>Widget          (3)

    Wie ist es möglich in alle referenzierten XMLs zu wechseln ?
    Sollte ich zuerst alle Widgets in Ebene 1 abarbeiten, dann Ebene 2,
    aber wie kann ich das anstellen ich verliere doch den Kontext wenn ich von einem XML ins nächste wechsele ?

    Ich lasse mal oben alles als Zitat stehen.
    Du hast recht, das könnte kompliziert werden. Theoretisch ist Rekursion schon der richtige Weg, kommt aber doch darauf an was als ausgabe rauskommen soll.

    "mehrere Widget Elemente in einem Dokument":
    Der einfachtes, aber auch das mächtigste/'gefährlichste' Möglichkeit ist:
    <xsl:template match="Widget">
     <xsl:apply-templates select="document(concat(@Path, '/', @Name, '.xml'))/rootElement" />
    </xsl:template>

    Das "erwischt" alle Widget im ersten Dokument, dann führt es die Templates für das gefundene XML aus. Wenn darin auch Widget vorkommt, wird das Template auf für diese instanziiert usw. immer weiter tiefer. Das Kontext geht an sich nicht verloren, weil du noch immer im obersten Widget bist.
    Das Ergebnis wird dann so sein wie deine Skizze (also was die Verschachtelung der Ausgabe angeht). "Gefährlich" kann es nur eben sein, wenn diese Verschachtelung der XMLs wirklich sehr tief geht.

    Kompliziert kann es dann werden, wenn du für die Ausgabe eine ganz andere Strukur brauchst und wenn die Path- und Name-Angaben relativ sind bzw. nicht den echten Pfad ergeben.
    Natürlich kommt es auch noch darauf an, was noch im Template für Widget für die Ausgabe stehen muss. (Bei bedarf kannst du bestimmte Sachen per Parameter auch immer weiter mitgeben.)

    Grüße
    Thomas

    1. Hallo,

      ich hoffe die Experten können mir helfen, ich glaube es ist ein ganz schön verzwicktes Problem.
      Gegeben ist ein Quell-XML, in dem es Elemente geben kann das weitere XMLs adressiert, in der Form:

      <Widget Name="PremiumCombiView_Audio_CD" FileNamePrefix="PremiumCombiView_Audio_CD" UniqueID="126551782039362000" Path="Container">

      Sprich das XML liegt unter dem Pfad
      Container/PremiumCombiView_Audio_CD.xml
      als Eigenschaft haben alle XML eine UniqueID.

      Das wäre an sich kein Problem mit einem rekursiven Template
      zu realiseren, das Problem ist das sich ja mehrere Widget
      Elemente in einem Dokument befinden können und ich immer nur
      das erste Element finde, in das nächste Dokument wechsele und wieder
      nach Widget Elementen suche. Wie ihr euch vorstellen könnt, kann sich das zu einer weiten Verzweigung führen.
      Folgende "Skizze" soll das Problem verdeutlichen.

      XML1  |   XML2   |   XML3   |  XMLx         Ebene

      Widget--->Widget--->Widget                   (1)
             |         |->Widget-->Widget          (2)
             |
             |->Widget------------>Widget          (3)

      Wie ist es möglich in alle referenzierten XMLs zu wechseln ?
      Sollte ich zuerst alle Widgets in Ebene 1 abarbeiten, dann Ebene 2,
      aber wie kann ich das anstellen ich verliere doch den Kontext wenn ich von einem XML ins nächste wechsele ?

      Ich lasse mal oben alles als Zitat stehen.
      Du hast recht, das könnte kompliziert werden. Theoretisch ist Rekursion schon der richtige Weg, kommt aber doch darauf an was als ausgabe rauskommen soll.

      "mehrere Widget Elemente in einem Dokument":
      Der einfachtes, aber auch das mächtigste/'gefährlichste' Möglichkeit ist:
      <xsl:template match="Widget">
      <xsl:apply-templates select="document(concat(@Path, '/', @Name, '.xml'))/rootElement" />
      </xsl:template>

      Hallo Thomas,

      danke für deine schnelle Antwort (ich bin der Poster Alex, habe mich jetzt registriert ;-) ).
      Mit deiner Lösung komme ich nun gut voran, das einzige mit dem ich jetzt ein Problem habe, das ich eine forlaufende Nummerierung der schon "gecheckten" XML Dokuemente erzeugen möchte. Ich habe mir erstmal beholfen, in dem mit dem Parameter"FrameID" das xsl:template aufrufe:

      <xsl:template match="/">
       <xsl:apply-templates select="WidgetStructure/ComposedWidget/Elements/Element/Widget" mode="FrameID">
               <xsl:with-param name="FrameID" select="0"/>
       </xsl:apply-templates>
      </xsl:template>

      das Template fürs Widget sieht so aus:

      <xsl:template match="Widget" mode="FrameID">
       <xsl:param name="FrameID"/>
       <xsl:value-of select="$FrameID"/>
       <xsl:apply-templates select="document(concat(@Path,'/',@FileNamePrefix,'.xml'))/WidgetStructure/ComposedWidget/Elements/Element/Widget" mode="FrameID">
        <xsl:with-param name="FrameID" select="$FrameID+1"/>
       </xsl:apply-templates>
      </xsl:template>

      So wenn das Template alle Dokumente für einen Root-Widgets abgearbeitet hat kehrt es zum Ausgangsdokument zurück und wendet das Template auf das nächste Widget Element an. Dabei wird auch mein Parameter "FrameID" wieder auf 0 gesetzt, eigentlich möchte ich eine fortlaufende Nummer. Gibt es da eine Lösung ? Variablen lassen sich ja nicht überschreiben oder doch ?! Ist es denkbar erstmal alle Widget Elemente im Root zu checkne und dann erst in die nächste Ebene hinunterzusteigen ?
      Das sind viele Fragen, ich hoffe ich nerve nicht ;-) ?

      Danke

      Grüße Alex

      1. Hallo,

        danke für deine schnelle Antwort (ich bin der Poster Alex, habe mich jetzt registriert ;-) ).

        Das freut mich! :)

        Mit deiner Lösung komme ich nun gut voran, das einzige mit dem ich jetzt ein Problem habe, das ich eine forlaufende Nummerierung der schon "gecheckten" XML Dokuemente erzeugen möchte. Ich habe mir erstmal beholfen, in dem mit dem Parameter"FrameID" das xsl:template aufrufe:

        So wenn das Template alle Dokumente für einen Root-Widgets abgearbeitet hat kehrt es zum Ausgangsdokument zurück und wendet das Template auf das nächste Widget Element an. Dabei wird auch mein Parameter "FrameID" wieder auf 0 gesetzt, eigentlich möchte ich eine fortlaufende Nummer. Gibt es da eine Lösung ?

        <xsl:template match="/">
         <xsl:apply-templates select="WidgetStructure/ComposedWidget/Elements/Element/Widget" mode="FrameID" />
        </xsl:template>

        <xsl:template match="Widget" mode="FrameID">
         <xsl:param name="FrameID">
          xsl:choose
           <xsl:when test="not(parent::Widget)"><xsl:value-of select="position()+count(preceding-sibling::Widget//Widget)" /></xsl:when>
           xsl:otherwise0</xsl:otherwise>
          </xsl:choose>
         </xsl:param>
         <xsl:value-of select="$FrameID"/>
         <xsl:apply-templates select="document(concat(@Path,'/',@FileNamePrefix,'.xml'))/WidgetStructure/ComposedWidget/Elements/Element/Widget" mode="FrameID">
          <xsl:with-param name="FrameID" select="$FrameID+1"/>
         </xsl:apply-templates>
        </xsl:template>

        Variablen lassen sich ja nicht überschreiben oder doch ?!

        Jein. z.B.
           <xsl:value-of select="$FrameID"/>
           <xsl:variable name="x" select="$FrameID+1" />
           <xsl:apply-templates select="...." mode="FrameID">
              <xsl:with-param name="FrameID" select="$x"/>
           </xsl:apply-templates>

        Der Wert von $x bleibt immer konstant, nämlich: $FrameID+1, dass $FrameID sich ändert, ist eine andere Sache. Die Variable wird bei jedem Aufruf des Templates neu erzeugt, und so weiss eine "frische" Variable nichts von einer "alten". Manchmal ist das verwirrend ;-)

        Grüße
        Thomas