Announcement

Collapse
No announcement yet.

XML Teilbäume per Attribut-Link und apply-templates verknüpfen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • XML Teilbäume per Attribut-Link und apply-templates verknüpfen

    Hallo

    Da ich schon einige Fragen hier gestellt habe, hoffe ich das noch eine ok geht.


    Vielleich hat jemand von euch eine Idee oder Hinweis.

    Ist Zustand: Habe ein XML Document, wo das Wurzelelement einen Container darstellt. Alle unmittelbaren Kinder bilden die Wurzel von weitern Bäumen (zb liste,artikel,usw). Die Elemente enthalten Attribute welche quasi einen Link auf die passende ID des nächsten Teilbaumes darstellt.

    Im Beispiel ist liste welche drei artikel enthält, welche wiederum type enthalten.

    Ziel der Lösung: Einen Ergebnisbaum in welchen die verlinkten Teilbäume (link) korrekt eingefügt werden und eventuelle Kinderelemente (zb desc) berücksichtigt wird.

    Die bisherige Lösung funktioniert - aber schlecht gelöst. Ich suche eine Lösung ohne xsl:template name="link" (bzw xsl:call-template name="link"),
    schön wäre ein xsl:apply-templates wo der select Attribut diese Aufgabe komplett übernehmen kann.

    Vielen Dank im Voraus



    Code:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <?xml-stylesheet type="text/xsl" href="artikel_liste.xsl" ?>
    <container>
      <liste id="1" linka="2" linkb="3">
          <name>Liste</name>
    	  <desc>Liste ueber allesmoegliche</desc>
      </liste>
      <artikel id="2" link="4">
        <name>Artikel A</name>
      </artikel>
      <artikel id="3" linka="5" linkb="6">
        <name>Artikel B</name>
      </artikel>
      <type id="4">Type A</type>
      <type id="5">Type B</type>
      <type id="6">Type C</type>
    </container>

    Meine bisherige funktionierende Lösung
    Code:
    <?xml version="1.0" encoding="iso-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    
    <xsl:template match="/">
     <html>
     <head>
     </head>
     <body>
     <xsl:apply-templates select="//*[@id='1']"/>
     </body>
     </html>
    </xsl:template>
    
    
    <xsl:template match="liste">
      name: <xsl:value-of select="."/><hr/>
      <xsl:call-template name="link"/> <hr/>
    </xsl:template>
    
    
    <xsl:template match="artikel">
      name: <xsl:value-of select="."/><hr/>
        <xsl:call-template name="link"/><hr/>
    </xsl:template>
    
    
    <xsl:template match="type">
      name: <xsl:value-of select="."/><br/>
      <xsl:call-template name="link"/><hr/>
    </xsl:template>
    
    
    <xsl:template match="desc">
      name: <xsl:value-of select="."/><br/>
      <xsl:call-template name="link"/><hr/>
    </xsl:template>
    
    
      <!--  Baut alle Zusammen -->
    <xsl:template name="link">
    
       <xsl:for-each select="@*">
    
         <xsl:if test="name()!='id'">
    	 <xsl:variable name="link" select="."/>
         <xsl:apply-templates select="//*[@id=$link]"/>
    	 </xsl:if>
       </xsl:for-each>   
       <xsl:apply-templates/>
       
    </xsl:template>
    
    
    <xsl:template match="*">
    </xsl:template>
    
    </xsl:stylesheet>
    Zuletzt editiert von mr_sol; 08.06.2011, 07:15.

  • #2
    Querverweise verarbeitet man mit XSLT am besten per xsl: key und der "key"-Funktion:
    Code:
    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
      
      <xsl:output method="html" indent="yes"/>
      
      <xsl:key name="by-id" match="container/*" use="@id"/>
      
      <xsl:template match="/">
       <html>
       <head>
         <title>Beispiel</title>
       </head>
       <body>
       <xsl:apply-templates select="key('by-id', '1')"/>
       </body>
       </html>
      </xsl:template> 
      
      <xsl:template match="liste | artikel | type">
        name: <xsl:value-of select="."/><hr/>
        <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])"/> <hr/>
      </xsl:template>
    
    </xsl:stylesheet>

    Comment


    • #3
      Hallo Martin

      Genial gelöst - mit key einen Schlüssel für alle id gesetzt....ist natürlich schneller

      Ein Kleinigkeit klappt noch nicht, das Ansprechen vom desc mit den gleichen xsl:apply-templates.
      Ist das überhaupt möglich? (sowohl über id als auch "normal" aufzurufen?)


      Code:
      <?xml version="1.0" encoding="iso-8859-1"?>
      <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
        
        <xsl:output method="html" indent="yes"/>
        
        <xsl:key name="by-id" match="container/*" use="@id"/>
        
        <xsl:template match="/">
         <html>
         <head>
           <title>Beispiel</title>
         </head>
         <body>
         <xsl:apply-templates select="key('by-id', '1')"/>
         </body>
         </html>
        </xsl:template> 
        
        <xsl:template match="liste | artikel | type">
          name: <xsl:value-of select="."/><hr/>
          <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])|*"/> <hr/>
        </xsl:template>
        
          <xsl:template match="desc">
          name: <xsl:value-of select="."/><hr/>
        </xsl:template>
        
        
      </xsl:stylesheet>

      Comment


      • #4
        Die Auswahl
        Code:
        <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])|*"/>
        sollte durchaus funktionieren, allerdings gibt das gesamte Stylesheet eventuell zu viel aus.
        Mit
        Code:
        <xsl:stylesheet
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          version="1.0">
          
          <xsl:output method="html" indent="yes"/>
          
          <xsl:key name="by-id" match="container/*" use="@id"/>
          
          <xsl:template match="/">
           <html>
           <head>
             <title>Beispiel</title>
           </head>
           <body>
           <xsl:apply-templates select="key('by-id', '1')"/>
           </body>
           </html>
          </xsl:template> 
          
          <xsl:template match="liste | artikel">
            Name: <xsl:value-of select="name"/><hr/>
            <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])|desc"/> <hr/>
          </xsl:template>
          
            <xsl:template match="desc">
            Beschreibung: <xsl:value-of select="."/><hr/>
          </xsl:template>
          
          <xsl:template match="type">
            Typ: <xsl:value-of select="."/>
          </xsl:template>
          
          
        </xsl:stylesheet>
        gibt Saxon 6.5.5 mit deinem Eingabedokument folgendes aus:
        Code:
        <html>
           <head>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        
              <title>Beispiel</title>
           </head>
           <body>
              Name: Liste
              <hr>
              Beschreibung: Liste ueber allesmoegliche
              <hr>
              Name: Artikel A
              <hr>
              Typ: Type A
              <hr>
              Name: Artikel B
              <hr>
              Typ: Type B
              Typ: Type C
              <hr>
              <hr>
           </body>
        </html>

        Comment


        • #5
          fast......

          Code:
          <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])|desc"/>
          liefert das richtige Ergebnis. Ich suche nach einer flexibleren Lösung.
          Hier müsste immer desc dabei sein. Das XML Document ist ja nur ein Beispiel, bei meinen Projekt sind wesendlich mehr "xsl:template match"....



          Code:
          <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])|*"/>
          Wie du geschrieben hast, gibt zuviel Information aus.


          Gibts ein Mittelding? Flexibel (ohne fixen Nodename) die child's als apply-templates aufrufen + Aufruf per links.

          PS: Sind Umlaute als Attributname erlaubt. (zb LinkÖstlich statt link1)
          Zuletzt editiert von mr_sol; 09.06.2011, 10:13.

          Comment


          • #6
            Wenn du klar erklärst, welche Ausgabe du willst, ist es sicherlich kein Problem, entsprechende Templates zu schreiben und diese mit passenden apply-templates auszuwählen. apply-templates select="node()", um alle Kindsknoten zu verarbeiten, oder apply-templates select="*", um alle Kindelemente zu verarbeiten, ist sicherlich der richtige Ansatz, so die Namen aller Kindelemente nicht bekannt sind.

            Comment


            • #7
              Hab die Lösung. So ist es perfekt, bin auf der Leitung gestanden.


              Code:
              <?xml version="1.0" encoding="iso-8859-1"?>
              <!-- **
              * @NAME: TREEBUILDER
              * @DESC: Baut ausgehend von einen XML Wurzelelement mit Hilfe von LinkAttributen einen Baum zusammen, 
              * wobei auch 'normale' Templates beruecksichtigt werden.
              *
              * @V0.1: 2011.05609
              *-->
              <xsl:stylesheet
                xmlns:ns="my:ns"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
                
              <xsl:output method="html" indent="yes"/>
              <xsl:key name="by-id" match="container/*" use="@id"/>
                
              <xsl:template match="/">
                 <html>
                 <head>
                   <title>Beispiel</title>
                 </head>
                 <body>
                 <xsl:apply-templates select="key('by-id', '1')"/>
                 </body>
                 </html>
                </xsl:template> 
                
                <xsl:template match="liste | artikel | type">
                  <xsl:value-of select="name()"/>: <xsl:value-of select="."/><hr/>
                  <xsl:apply-templates select="key('by-id', @*[not(local-name() = 'id')])|node()"/> <hr/>
                </xsl:template>
                
                  <xsl:template match="desc">
                  <xsl:value-of select="name()"/>: <xsl:value-of select="."/><hr/>
                </xsl:template>
                
                <!-- Muell abfangen -->
                 <xsl:template match="node()">
                 </xsl:template>
              
              </xsl:stylesheet>

              Nochmals vielen Dank für deine Hilfe

              Comment


              • #8
                Habe jetzt bei Testen doch noch ein Problem entdeckt und musste meine XML Dateistruktur umbauen und stehe vor den gleichen Problem.

                Statt ein Element mit mehreren Link Attributen muss ich Linkelemente einführen.
                link[@linknode] passt aber nicht.


                Code:
                <?xml version="1.0" encoding="ISO-8859-1"?>
                <?xml-stylesheet type="text/xsl" href="artikel_liste.xsl" ?>
                <hcp>
                  <liste id="1">
                      <link id="10" linknode="2"/>
                      <link id="11" linknode="3"/>
                      <name>Liste</name>
                      <desc>Liste ueber allesmoegliche</desc>
                  </liste>
                  <artikel id="2">
                    <link id="12" linknode="4"/>
                    <name>Artikel A</name>
                  </artikel>
                  <artikel id="3">
                    <link id="13" linknode="5"/>
                    <link id="14" linknode="6"/>
                    <name>Artikel B</name>
                  </artikel>
                  <type id="4">Type A</type>
                  <type id="5">Type B</type>
                  <type id="6">Type C</type>
                </hcp>

                Mein Code-Ansatz

                Code:
                <?xml version="1.0" encoding="iso-8859-1"?>
                <!-- **
                * @NAME: TREEBUILDER
                * @DESC: Baut ausgehend von einen XML Wurzelelement mit Hilfe von LinkAttributen einen Baum zusammen, 
                * wobei auch 'normale' Templates beruecksichtigt werden.
                *
                * @V0.1: 2011.06.08 Element mit allen LinkID in Attributen
                * @V0.2: 2011.06.09 Baut auf neue LinkElementen auf
                *-->
                <xsl:stylesheet
                  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                  version="1.0">
                  
                <xsl:output method="html" indent="yes"/>
                <xsl:key name="by-id" match="hcp/*" use="@id"/>
                  
                <xsl:template match="/">
                   <html>
                   <head>
                     <title>Beispiel</title>
                   </head>
                   <body>
                   <xsl:apply-templates select="key('by-id', '1')"/>
                   </body>
                   </html>
                  </xsl:template> 
                  
                  <xsl:template match="liste | artikel | type">
                    <xsl:value-of select="name()"/>: <xsl:value-of select="."/><hr/>
                    <xsl:apply-templates select="key('by-id', link[@linknode])|node()"/> <hr/>
                  </xsl:template>
                  
                    <xsl:template match="desc">
                    <xsl:value-of select="name()"/>: <xsl:value-of select="."/><hr/>
                  </xsl:template>
                  
                  <!-- Muell abfangen *-->
                   <xsl:template match="node()">
                   </xsl:template>
                
                </xsl:stylesheet>

                Danke im voraus.

                Comment


                • #9
                  Nimm
                  Code:
                  select="key('by-id', link/@linknode)"

                  Comment


                  • #10
                    Vielen Dank Martin, klappt.

                    Comment

                    Working...
                    X