views:

127

answers:

3

I am using a heavy stylesheet with a lot of recurring transformations, so I thought it would be smart to reuse the same chunks of code, so I would not need to make the same changes at a bunch of different places. So I discovered , but -alas- it won't allow me to do it. When trying to run it in Sonic Workbench I get the following error:

An xsl:for-each element must not contain an xsl:import element

This is my stylesheet code:

<xsl:template match="/">
  <InboundFargoMessage>
   <EdiSender>
    <xsl:value-of select="TransportInformationMessage/SenderId"/>
   </EdiSender>
   <EdiReceiver>
    <xsl:value-of select="TransportInformationMessage/RecipientId"/>
   </EdiReceiver>
      <EdiSource>PORLOGIS</EdiSource>
      <EdiDestination>FARGO</EdiDestination>
   <Transportations>
    <xsl:for-each select="TransportInformationMessage/TransportUnits/TransportUnit">
     <xsl:import href="TransportCDMtoFDM_V0.6.xsl"/>
    </xsl:for-each>
    <xsl:for-each select="TransportInformationMessage/Waybill/TransportUnits/TransportUnit">
     <xsl:import href="TransportCDMtoFDM_V0.6.xsl"/>
    </xsl:for-each>
   </Transportations>
  </InboundFargoMessage>
 </xsl:template>
</xsl:stylesheet>

I will leave out the child xsl-sheets for now, as the problem appears to be happening at the base.

If I cannot use xsl:import, is there any option of reuse?

A: 

Each of included XSL files should contain a template(s).

The main file includes the others in the beginning and then calls the templates with call-template or apply-templates from various places.

GSerg
+3  A: 

If I cannot use xsl:import, is there any option of reuse?

You can use <xsl:import>.

All <xsl:import> elements must be the first element children of <xsl:stylesheet>

As an alternative, an <xsl:include> element has to be globally defined (a child of <xsl:stylesheet>) but can be preceded by any other xslt instruction that can be placed globally.

You need to be aware of and understand well the rules of using these two XSLT instructions. I'd recommend reading a good book on XSLT.

The main unit of reusability in XSLT is the template (<xsl:template>).

The importing stylesheet can use (via <xsl:call-template> or <xsl:apply-templates>) any template that is defined in any imported stylesheet.

Dimitre Novatchev
Thnx. I am still unsure how to apply templates in my case, as they seem to need a match, whereas I just need to call a chunk of xsl-code at certain nodes of the base xsl sheet. Also: If I define the templates within the same stylesheet, will I then not need any import statements?
Fedor Steeman
@Fedor-Steeman: You *need* to read a good book about XSLT. The same when someone doesn't know C# but wants to write programs in C#.
Dimitre Novatchev
OK, I will ask my boss for a good book after I solved this problem, or go buy one myself. For now I just need to have this solved asap, and I am pretty close. The only thing I need now is how to leave out empty elements.
Fedor Steeman
@Fedor-Steeman: Ask a new question about this.
Dimitre Novatchev
Alrighty: http://stackoverflow.com/questions/2706202/xslt-how-to-exclude-empty-nodes-from-my-result
Fedor Steeman
Marked as solution for setting me on the right track...
Fedor Steeman
A: 

Thanks for all the suggestions, which were somewhat helpful, but allow me formulate a complete answer. As suggested, the answer to the question of re-use lies in the xsl:templates. Templates can be defined by enclosing them within . Then, whereever necessary, they can be summoned by adding a element. Also, they can be put into separate xsl sheets, as long as they are imported at the top of the parent xsl sheet.

Thus, the solution to my questions looks as follows:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:far="http://www.itella.com/fargo/fargogate/" xmlns:a="http://tempuri.org/XMLSchema.xsd" xmlns:p="http://tempuri.org/XMLSchema.xsd"&gt;
     <xsl:import href="TransportCDMtoFDM_V0.6.xsl"/>
     <xsl:template match="/">
        <InboundFargoMessage>
        <EdiSender>
            <xsl:value-of select="TransportInformationMessage/SenderId"/>
        </EdiSender>
        <EdiReceiver>
            <xsl:value-of select="TransportInformationMessage/RecipientId"/>
        </EdiReceiver>
        <EdiSource>PORLOGIS</EdiSource>
        <EdiDestination>FARGO</EdiDestination>
        <Transportations>
            <xsl:for-each select="TransportInformationMessage/TransportUnits/TransportUnit">
                <xsl:call-template name="transport"/>
            </xsl:for-each>
            <xsl:for-each select="TransportInformationMessage/Waybill/TransportUnits/TransportUnit">
                <xsl:call-template name="transport"/>
            </xsl:for-each>
        </Transportations>
    </InboundFargoMessage>
 </xsl:template>

Where the file 'TransportCDMtoFDM_V0.6.xsl' contains the template called "transport".

There is just one problem left: Using templates, all the nodes mentioned within the template are used, even if they are empty. So the remaining question is how to leave out the empty nodes?

Fedor Steeman