Gern stehe ich zur fachlichen Unterstützung in XML-Technologien, C#.NET, VisualBasic.NET und Java zur Verfügung. Sprechen Sie mich einfach an: Mail oder ☎ 0151 . 750 360 61


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). Die folgende Logik setzt daher auf jenen Node(s) auf, die kein @refid-Attribut 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="TU10" id="10">
   <Bauteil name="RS9" id="9">
      <Bauteil name="PQ8" id="8">
         <Bauteil name="NO7" id="7">
            <Bauteil name="LM6" id="6">
               <Bauteil name="IK5" id="5">
                  <Bauteil name="GH4" id="4">
                     <Bauteil name="EF3" id="3">
                        <Bauteil name="CD2" id="2">
                           <Bauteil name="AB1" id="1"/>
                        </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[not(@refid)]"/>                
    </xsl:template>
    <xsl:template match="info">
        <xsl:variable name="vid" select="@id"/>		
        <xsl:variable name="vname" select="@name"/>
        <Bauteil name="{$vname}" id="{$vid}">           
            <xsl:apply-templates 
                select="/ROOT/info[@refid=$vid]"/>
        </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 $vid := $element/@id
  return
    <Bauteil name="{$element/@name}" id="{$vid}">
      {
        if (exists($element/../info[@refid = $vid]))
        then (
          local:generate_tree($element/../info[@refid = $vid])
        )
        else ()
      }
    </Bauteil>
};
for $n in /ROOT/info[not(@refid)]
return local:generate_tree($n)

XSL-FO Darstellung in PDF

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

pic/referenzierungen.png

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="60mm">
                    <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="1cm" 
                        text-align="center">Bauteile</fo:block>
                    <xsl:apply-templates select="/ROOT/info[not(@refid)]"/> 
                </fo:flow>
            </fo:page-sequence>
        </fo:root>
    </xsl:template>
    <xsl:template match="info">
        <xsl:variable name="vid" select="@id"/>		
        <fo:table start-indent="5mm">
            <fo:table-body>
                <fo:table-row>
                    <fo:table-cell border-color="lightgrey" 
                        border-width="0.5pt" 
                        border-style="solid">                       
                        <fo:block text-align="left">
                            <xsl:value-of select="@name"/>
                        </fo:block>            
                        <xsl:apply-templates 
                            select="/ROOT/info[@refid=$vid]"/>            
                    </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
    return
        <fo:table
            start-indent="5mm">
            <fo:table-body>
                <fo:table-row>
                    <fo:table-cell
                        border-color="lightgrey"
                        border-width="0.5pt"
                        border-style="solid">
                        <fo:block
                            text-align="left">
                            {data($element/@name)}
                        </fo:block>
                        {
                            if (exists($element/../info[@refid = $vid]))
                            then
                                (
                                local:generate_fo_table
                                ($element/../info[@refid = $vid])
                                )
                            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="60mm">
            <fo:region-body/>
        </fo:simple-page-master>
    </fo:layout-master-set>
    {
        for $n in /ROOT/info[not(@refid)]
        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 / 15. November 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