Writing the Style Sheet


The most interesting side of the transformation is not performed in Java, but is performed by the XSLT style sheet reproduced in Listing 5.10.

Listing 5.10 xml2edi.xsl
 <?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="xml"/> <xsl:template match="/">    <Message>       <xsl:apply-templates/>    </Message> </xsl:template> <xsl:template name="format-date">    <xsl:param name="date"/>    <xsl:value-of select="substring($date,1,4)"/>    <xsl:value-of select="substring($date,6,2)"/>    <xsl:value-of select="substring($date,9,2)"/> </xsl:template> <xsl:template name="Address">    <xsl:param name="code"/>    <xsl:param name="value"/>    <Segment tag="NAD">       <Simple><xsl:value-of select="$code"/></Simple>       <Composite><Simple/></Composite>       <Composite><Simple/></Composite>       <Composite>          <Simple>             <xsl:value-of select="$value/Name"/>          </Simple>       </Composite>       <Composite>          <Simple>             <xsl:value-of select="$value/Address/Street"/>          </Simple>       </Composite>       <Simple>          <xsl:value-of select="$value/Address/Locality"/>       </Simple>       <Simple>          <xsl:value-of select="$value/Address/Region"/>       </Simple>       <Simple>          <xsl:value-of select="$value/Address/PostalCode"/>       </Simple>       <Simple>          <xsl:value-of select="$value/Address/Country"/>       </Simple>    </Segment> </xsl:template> <xsl:template match="Order">    <Segment tag="UNH">       <Simple>1</Simple>       <Composite>          <Simple>ORDERS</Simple>          <Simple>D</Simple>          <Simple>96A</Simple>          <Simple>UN</Simple>       </Composite>    </Segment>    <Segment tag="BGM">       <Composite>          <Simple>220</Simple>       </Composite>       <Simple>          <xsl:value-of select="Reference"/>       </Simple>       <Simple>9</Simple>       <Simple>          <xsl:choose>             <xsl:when test="@confirm=true()">AB</xsl:when>             <xsl:otherwise>NA</xsl:otherwise>          </xsl:choose>       </Simple>    </Segment>    <Segment tag="DTM">       <Composite>          <Simple>137</Simple>          <Simple>             <xsl:call-template name="format-date">                <xsl:with-param name="date" select="Date"/>             </xsl:call-template>          </Simple>          <Simple>102</Simple>       </Composite>    </Segment>    <xsl:if test="DeliverBy">       <Segment tag="DTM">          <Composite>             <Simple>61</Simple>             <Simple>                <xsl:call-template name="format-date">                   <xsl:with-param name="date"                                   select="DeliverBy"/>                </xsl:call-template>             </Simple>             <Simple>102</Simple>          </Composite>       </Segment>    </xsl:if>    <xsl:call-template name="Address">       <xsl:with-param name="code" select="'BY'"/>       <xsl:with-param name="value" select="Buyer"/>    </xsl:call-template>    <xsl:call-template name="Address">       <xsl:with-param name="code" select="'SE'"/>       <xsl:with-param name="value" select="Seller"/>    </xsl:call-template>    <xsl:for-each select="Lines/Product">       <Segment tag="LIN">          <Simple><xsl:value-of select="position()"/></Simple>       </Segment>       <Segment tag="PIA">          <Simple>5</Simple>          <Composite>             <Simple>                <xsl:value-of select="Code"/>             </Simple>             <xsl:choose>                <!-- ISSN for magazines -->                <xsl:when test="Code/@type='ISSN'">                   <Simple>IS</Simple>                </xsl:when>                <!-- or ISBN for books -->                <xsl:otherwise>                   <Simple>IB</Simple>                </xsl:otherwise>             </xsl:choose>          </Composite>       </Segment>       <Segment tag="QTY">          <Composite>             <Simple>21</Simple>             <Simple><xsl:value-of select="Quantity"/></Simple>          </Composite>       </Segment>       <Segment tag="PRI">          <Composite>             <Simple>AAA</Simple>             <Simple><xsl:value-of select="Price"/></Simple>             <Simple/>             <Simple>SRP</Simple>          </Composite>       </Segment>    </xsl:for-each>    <Segment tag="UNS">       <Simple>S</Simple>    </Segment>    <xsl:variable name="nr-lines"                  select="count(Lines/Product)"/>    <Segment tag="CNT">       <Composite>          <Simple>3</Simple>          <Simple>             <xsl:value-of select="$nr-lines"/>          </Simple>       </Composite>    </Segment>    <Segment tag="UNT">       <Simple>          <xsl:choose>             <xsl:when test="DeliverBy">                <xsl:value-of select="9 + ($nr-lines * 4)"/>             </xsl:when>             <xsl:otherwise>                <xsl:value-of select="8 + ($nr-lines * 4)"/>             </xsl:otherwise>          </xsl:choose>       </Simple>       <Simple>1</Simple>    </Segment> </xsl:template> </xsl:stylesheet> 

The bulk of the transformation is in the template matching the Order element. The template lists all the segments in the EDIFACT order. Note that this style sheet is specific to the order message, so you would need a different style sheet for other messages.

Where appropriate, the template uses xsl:choose to convert between XML and EDIFACT codes:

 <Segment tag="BGM">    <Composite>       <Simple>220</Simple>    </Composite>    <Simple>       <xsl:value-of select="Reference"/>    </Simple>    <Simple>9</Simple>    <Simple>       <xsl:choose>          <xsl:when test="@confirm=true()">AB</xsl:when>          <xsl:otherwise>NA</xsl:otherwise>       </xsl:choose>    </Simple> </Segment> 

The loop over the product lines demonstrates clearly that the EDIFACT structure is flat. In XML, the product lines are organized in a hierarchy of elements. In EDIFACT, however, it's a list of segments:

 <xsl:for-each select="Lines/Product">    <Segment tag="LIN">       <!-- deleted -->    </Segment>    <Segment tag="PIA">       <!-- deleted -->    </Segment>    <Segment tag="QTY">       <!-- deleted -->    </Segment>    <Segment tag="PRI">       <!-- deleted -->    </Segment> </xsl:for-each> 

The total number of segments (which we need for the UNT segment) depends on the number of product lines and whether the optional DeliverBy element is present in the order:

 <Segment tag="UNT">    <Simple>       <xsl:choose>          <xsl:when test="DeliverBy">             <xsl:value-of select="9 + ($nr-lines * 4)"/>          </xsl:when>          <xsl:otherwise>             <xsl:value-of select="8 + ($nr-lines * 4)"/>          </xsl:otherwise>       </xsl:choose>    </Simple>    <Simple>1</Simple> </Segment> 

The style sheet also declares a special template to reformat the date. In XML, the date is typically written with minus characters between the year, month, and day. In contrast, EDIFACT (always obsessed with size ) compresses it:

 <xsl:template name="format-date">    <xsl:param name="date"/>    <xsl:value-of select="substring($date,1,4)"/>    <xsl:value-of select="substring($date,6,2)"/>    <xsl:value-of select="substring($date,9,2)"/> </xsl:template> 

This template accepts a parameter, so it can be called similar to a function:

 <xsl:call-template name="format-date">    <xsl:with-param name="date" select="Date"/> </xsl:call-template> 

Applied XML Solutions
Applied XML Solutions
ISBN: 0672320541
EAN: 2147483647
Year: 1999
Pages: 142

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net