Announcement

Collapse
No announcement yet.

Nodes umsortieren

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

  • Nodes umsortieren

    Hi,

    mein XSLT funktioniert - dank Martin Honnen - soweit ganz gut:

    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:the-abc="https://www.abc.org/the-abc" 
        xmlns:the-gen="https://www.abc.org/the-GEN" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="
            https://www.abc.org/the-GEN the-gen-1.2.xsd 
            https://www.abc.org/the-abc the-abc-5.1.xsd">
        
        <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
        
        <xsl:variable name="Prefix" select="'tblabc_'"/>
        
        <xsl:template match="/">
            <xsl:apply-templates select="dataroot/tblabc_theabc" mode="root"/>
        </xsl:template>
        
        <!-- Root element -->
        <xsl:template match="*" mode="root">
            <the-abc:theabc 
                xmlns:the-abc="https://www.abc.org/the-abc" 
                xmlns:the-gen="https://www.abc.org/the-GEN" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                xsi:schemaLocation="
                    https://www.abc.org/the-GEN the-gen-1.2.xsd 
                    https://www.abc.org/the-abc the-abc-5.1.xsd">
            <xsl:for-each select="child::node()">
                <xsl:choose>
                    <!-- Default processing -->
                    <xsl:when test="child::node()/child::node()">
                        <xsl:apply-templates select="." mode="container"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="." mode="element"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
            </the-abc:theabc>
        </xsl:template>
        
        <!-- Container element -->
        <xsl:template match="*" mode="container">
            <xsl:variable name="Container">
                <xsl:apply-templates select="." mode="translateContainer"/>
            </xsl:variable>
            <xsl:if test="not(string-length($Container) = 0)">
                <xsl:element name="{$Container}">
                    <xsl:for-each select="child::node()">
                        <xsl:choose>
                        <xsl:when test="child::node()/child::node()">
                            <xsl:choose>
                            <!-- Special containers -->
                            <xsl:when test="local-name() = 'tblabc_SenderAddress'">
                                <xsl:apply-templates select="." mode="address"/>
                            </xsl:when>
                            <xsl:when test="local-name() = 'tblabc_DeliveryAddress'">
                                <xsl:apply-templates select="." mode="address"/>
                            </xsl:when>
                            <!-- Default container -->
                            <xsl:otherwise>
                                <xsl:apply-templates select="." mode="container"/>
                            </xsl:otherwise>
                            </xsl:choose>
                        </xsl:when>
                        <xsl:otherwise>
                            <!-- Default element -->
                            <xsl:apply-templates select="." mode="element"/>
                        </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:element>
            </xsl:if>
        </xsl:template>
        
        <!-- Address container -->
        <xsl:template match="*" mode="address">
            <xsl:if test="not(local-name(preceding-sibling::*[1]) = local-name(.))">
                <xsl:variable name="Container">
                    <xsl:apply-templates select="." mode="translateContainer"/>
                </xsl:variable>
                <xsl:element name="{$Container}">
                    <xsl:for-each select="../child::*/child::AddressLine">
                        <xsl:apply-templates select="." mode="element"/>
                    </xsl:for-each>
                </xsl:element>
            </xsl:if>
        </xsl:template>
        
        <!-- Value element -->
        <xsl:template match="*" mode="element">
            <xsl:if test="not(substring-after(local-name(), substring-before(local-name(), 'Id')) = 'Id')">
                <xsl:variable name="Element">
                    <xsl:apply-templates select="." mode="translateElement"/>
                </xsl:variable>
                <xsl:if test="not(string-length($Element) = 0)">
                    <xsl:element name="{$Element}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:if>
            </xsl:if>
        </xsl:template>
        
        <!-- ================================================================================ -->
        <!-- Export from database                                                             -->
        <!-- ================================================================================ -->
    
        <!-- Container translation -->
        <xsl:template match="*" mode="translateContainer">
            <xsl:choose>
            <xsl:when test="local-name() = 'tblabc_theabc'">  <xsl:value-of select="'the-abc:theabc'"/>   </xsl:when>
            </xsl:choose>
        </xsl:template>
        
        <!-- Value element translation -->
        <xsl:template match="*" mode="translateElement">
            <xsl:choose>
            <xsl:when test="local-name() = 'abcFilePrefix'">	<xsl:value-of select="'the-abc:abcFilePrefix'"/>	</xsl:when>
            </xsl:choose>
        </xsl:template>
    
    </xsl:stylesheet>
    Leider muß ich während der Transformation ab und zu auch noch für eine bestimmte Reihenfolge sorgen. Ich habe versucht in das Container-Template eine Ausfallbehandlung einzufügen:

    Code:
        <!-- Special order -->
        <!--
        <xsl:when test="local-name(.) = 'theCode' and local-name(following-sibling::node()) = 'tblabc_SenderAddress'">
            <xsl:apply-templates select="following-sibling::node()" mode="address"/>
            <xsl:apply-templates select="node()" mode="element"/>
        </xsl:when>
        <xsl:when test="local-name(.) = 'theCode' and local-name(following-sibling::node()) = 'tblabc_DeliveryAddress'">
            <xsl:apply-templates select="following-sibling::node()" mode="address"/>
            <xsl:apply-templates select="node()" mode="element"/>
        </xsl:when>
        -->
    Das hat natürlich nicht funktioniert.

    Die perfekte Lösung wäre vermutlich ein separates Template (ähnlich der Translate-Templates), in dem ich die Spezialfälle sauber auflisten könnte, auch um deren Wartbarkeit zu gewährleisten.

    Wenn ich das richtig sehen sollte, müßte dieses separate Template im Container-Element vor der Standard-Behandlung angesiedelt werden, alle betroffenen Elemente enthalten (damit er nicht in eine falsche Rekursion läuft) und die betroffenen Elemente entsprechend transformieren.

    Als Quasi-Code also sowas wie "Wenn 'theCode' oder 'tblabc_SenderAddress' oder 'tblabc_DeliveryAddress', dann call-template 'reorder'." - und in diesem Template müßten die Nodes dann ähnlich wie im Container-Element verarbeitet werden.

    Das führte zwar zu einer gewissen Duplizierung von XSLT-Code, aber wäre vmtl am zielführendsten.

    Sehe ich das richtig? Gibt es ggf einen besseren Weg um das gewünschte Ziel zu erreichen?
    --
    Cheers Vince
Working...
X