XSL-Übersicht / xsl:apply-templates bei Referenzierungen

xsl:apply-templates bei Referenzierungen

xsl:apply-templates bei Referenzierungen

➪ Sinnvoll kann der Einsatz von xsl:apply-templates und xsl:template match bei wiederholten Referenzierungen im XML-Input Dokument sein.

Auf dieser Seite:

Siehe auch:

Nehmen Sie als Beispiel das folgende XML-Dokument, in dessen info-Elementen die @refid-Attribute sich auf @id-Attribute anderer Elemente beziehen. Dabei setze ich voraus, dass sich keine Rekursionen ergeben (so darf <info id="10"> keine @refid="1" aufweisen).


<ROOT>
    <info id="1" refid="2" name="AB1"/>
    <info id="2" refid="3" name="CD2"/>
    <info id="3" refid="4" name="EF3"/>
    <info id="4" refid="5" name="GH4"/>
    <info id="5" refid="6" name="IK5"/>
    <info id="6" refid="7" name="LM6"/>
    <info id="7" refid="8" name="NO7"/>
    <info id="8" refid="9" name="PQ8"/>
    <info id="9" refid="10" name="RS9"/>
    <info id="10" name="TU10"/>
</ROOT>

Aus diesen gegenseitigen Abhängigkeiten ergibt sich eine Verschachtelung, die sich so darstellen lässt:


<Bauteil name="AB1" id="1">
   <Bauteil name="CD2" id="2">
      <Bauteil name="EF3" id="3">
         <Bauteil name="GH4" id="4">
            <Bauteil name="IK5" id="5">
               <Bauteil name="LM6" id="6">
                  <Bauteil name="NO7" id="7">
                     <Bauteil name="PQ8" id="8">
                        <Bauteil name="RS9" id="9">
                           <Bauteil name="TU10" id="10"/>
                        </Bauteil>
                     </Bauteil>
                  </Bauteil>
               </Bauteil>
            </Bauteil>
         </Bauteil>
      </Bauteil>
   </Bauteil>
</Bauteil>

Das XSLT-Mapping

Um die Input-Struktur in die verschachtelte Zielstruktur zu konvertieren, können Sie mit diesem XSL-Stylesheet arbeiten:


<xsl:stylesheet 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/ROOT">        
        <xsl:apply-templates 
             select="/ROOT/info[@id='1']"/>        
    </xsl:template>
    <xsl:template match="info">
        <xsl:variable name="vid" select="@id"/>		
        <xsl:variable name="vidref" select="@refid"/>        
        <Bauteil name="{@name}" id="{$vid}">           
            <xsl:apply-templates 
                 select="/ROOT/info[@id=$vidref]"/>
        </Bauteil>
    </xsl:template>
</xsl:stylesheet>

Das XQuery-Mapping

Das vorhin beschriebene Ergebnis lässt sich in XQuery mit einem rekursiven Funktionsaufruf erzeugen.


xquery version '3.0';
declare function local:generate_tree($element as node()) {
  let $vidref := $element/@refid
  return
    <Bauteil name="{$element/@name}" id="{$element/@id}">
      {
        if (exists($element/../info[@id = $vidref]))
        then (
          local:generate_tree($element/../info[@id = $vidref])
        )
        else ()
      }
    </Bauteil>
};
for $n in /ROOT/info[@id = '1']
return local:generate_tree($n)

XSL-FO Darstellung in PDF

Die Verschachtelung lässt sich auch via XSL-FO in PDF gut darstellen.

Zur Konvertierung verwenden Sie dieses XSL-FO:


<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fo="http://www.w3.org/1999/XSL/Format"
    version="1.0">
    <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <fo:root >
      <fo:layout-master-set>
        <fo:simple-page-master master-name="sample" 
          page-height="297mm"
          page-width="210mm"
          margin="20mm">
          <fo:region-body/>
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="sample">
        <fo:flow flow-name="xsl-region-body">
          <fo:block/>
          <fo:block space-before="7cm" 
                    space-after="2cm" 
                    text-align="center">Bauteile</fo:block>
          <xsl:apply-templates select="/ROOT/info[@id='1']"/> 
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
  <xsl:template match="info">
    <xsl:variable name="vid" select="@id"/>		
    <xsl:variable name="vidref" select="@refid"/> 
    <fo:table start-indent="1cm">
      <fo:table-body>
        <fo:table-row>
          <fo:table-cell border-color="green" 
                         border-width="0.5pt" 
                         border-style="solid">
            <fo:block space-after="5mm" space-before="5mm">
              <xsl:value-of select="@name"/>
            </fo:block>            
            <xsl:apply-templates select="/ROOT/info[@id=$vidref]"/>            
          </fo:table-cell>
        </fo:table-row>
      </fo:table-body>
    </fo:table>		
  </xsl:template>
</xsl:stylesheet>

XQuery: Darstellung in PDF

Dasselbe Resultat können Sie auch mit XQuery erzielen:


xquery version '3.0';
declare namespace fo ="http://www.w3.org/1999/XSL/Format";
declare function local:generate_fo_table($element as node()) {  
   let $vid := $element/@id
   let $vidref := $element/@refid          
   return 
   <fo:table start-indent="1cm">
    <fo:table-body>
      <fo:table-row>
        <fo:table-cell border-color="green" 
                       border-width="0.5pt" 
                       border-style="solid">
          <fo:block space-after="5mm" 
                    space-before="5mm">
            {data($element/@name)}
          </fo:block>           
          {           
            if (exists ($element/../info[@id=$vidref]))
            then (
              local:generate_fo_table
                        ($element/../info[@id=$vidref])
            )
            else ()          
          }
        </fo:table-cell>
      </fo:table-row>
    </fo:table-body>
  </fo:table>		
};
<fo:root>
 <fo:layout-master-set>
    <fo:simple-page-master
      master-name="sample"
      page-height="297mm"
      page-width="210mm"
      margin="20mm">
      <fo:region-body/>
    </fo:simple-page-master>
  </fo:layout-master-set>
 {
 for $n in /ROOT/info[@id='1'] return 
   <fo:page-sequence master-reference="sample">
    <fo:flow flow-name="xsl-region-body">      
      <fo:block
        space-before="7cm"
        space-after="2cm"
        text-align="center">Bauteile</fo:block>
        {local:generate_fo_table($n)}
    </fo:flow>
  </fo:page-sequence>
 }
</fo:root>

wg / 16. Oktober 2018



Fragen? Anmerkungen? Tipps?

Bitte nehmen Sie Kontakt zu mir auf.






Vielen Dank für Ihr Interesse an meiner Arbeit.


V.i.S.d.P.: Wilfried Grupe * Klus 6 * 37643 Negenborn

☎ 0151. 750 360 61 * eMail: info10@wilfried-grupe.de

www.wilfried-grupe.de/XSL_apply_templates_referenzierungen.html