Question

I have two xslt transformations to apply to an xml message.

<?xml version="1.0" encoding="UTF-8"?>    
    <ListOfBipBoxfldrlbls>
      <Batch>   
        <ListOfFolder>
          <Folder>
            <FolderNum>Fldr1</FolderNum>             
            <BoxNumber>Box1</BoxNumber>
            <BatchNumber>Batch</BatchNumber>
          </Folder>
          <Folder>
            <FolderNum>Fldr2</FolderNum>       
            <BoxNumber>Box1</BoxNumber>  
            <BatchNumber>Batch</BatchNumber>        
          </Folder>
          <Folder>
            <FolderNum>Fldr3</FolderNum>        
            <BoxNumber>Box1</BoxNumber> 
            <BatchNumber>Batch</BatchNumber>
          </Folder>
          <Folder>
            <FolderNum>Fldr1</FolderNum>
            <BoxNumber>Box2</BoxNumber>
            <BatchNumber>Batch</BatchNumber>
          </Folder>
          <Folder>
            <FolderNum>Fldr2</FolderNum>
            <BoxNumber>Box2</BoxNumber>
            <BatchNumber>Batch</BatchNumber>
          </Folder>
          <Folder>
            <FolderNum>Fldr3</FolderNum>
            <BoxNumber>Box2</BoxNumber>
            <BatchNumber>Batch</BatchNumber>
          </Folder>
          <Folder>
            <FolderNum>Fldr4</FolderNum>
            <BoxNumber>Box2</BoxNumber>
            <BatchNumber>Batch</BatchNumber>
          </Folder>
          </ListOfFolder>
        <ListOfBox>
          <Box>
            <BatchNumber>Batch</BatchNumber>
            <BoxNumber>Box1</BoxNumber>               
          </Box>
          <Box>     
            <BatchNumber>Batch</BatchNumber>
            <BoxNumber>Box2</BoxNumber>                
          </Box>
        </ListOfBox>
      </Batch>  
    </ListOfBipBoxfldrlbls>

Expected Output :

 Box1                     Box1 Fldr1       Box1 Fldr2

 Box1 Fldr3              Box2              Box2 Fldr1

 Box2 Fldr2              Box2 Fldr3        Box2 Fldr4

Here is my xsl

<?xml version="1.0"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">
    <xsl:variable name="phase-1-result">
        <xsl:apply-templates select="/" mode="phase-1"/>
    </xsl:variable>
    <xsl:apply-templates select="$phase-1-result" mode="phase-2"/>
</xsl:template>

<xsl:template match="/" mode="phase-1">
  <ListofLabels>
    <xsl:for-each select="ListOfBipBoxfldrlbls/Batch/ListOfFolder/Folder">
      <Label>        
        <FolderNum><xsl:value-of select="FolderNum"/></FolderNum>
        <Box><xsl:value-of select="BoxNumber"/></Box>
        <Batch><xsl:value-of select="BatchNumber"/></Batch>
      </Label>
    </xsl:for-each>
    <xsl:for-each select="ListOfBipBoxfldrlbls/Batch/ListOfBox/Box">
      <Label>        
        <Box><xsl:value-of select="BoxNumber"/></Box>
        <Batch><xsl:value-of select="BatchNumber"/></Batch>
      </Label>
    </xsl:for-each>
  </ListofLabels>
</xsl:template>

<xsl:template match="$phase-1-result/ListofLabels/Label" mode="phase-2">    
    <xsl:variable name="columns" select="3" />
    <TABLE border="1">
      <xsl:for-each select="$phase-1-result/ListofLabels/Label[position() mod $columns = 1]"> 
         <TR>
           <xsl:for-each select=".|following-sibling::$phase-1-result/ListofLabels/Label[position() &lt; $columns]">
             <TD>
               <xsl:value-of select="." />
             </TD>
           </xsl:for-each> 
         </TR> 
      </xsl:for-each> 
    </TABLE> 
    </xsl:template>

</xsl:stylesheet>

I am trying to restructure the XML in the first pass and store the result in a variable "$phase-1-result" and format in the second pass using the new structure.

The problem is xmlspy is not recognizing the Variable. it is show it as undefined variable and Error: Unexpected token "$phase-1-result/ListofLabels/Label".

Can some one help me identify the Issue.

Thanks in advance.

Was it helpful?

Solution

You only need to use the variable in the initial <xsl:apply-templates select="$phase-1-result" mode="phase-2" />. After that you're "inside" the phase 1 result tree, and the match expressions and further selects don't need to use the variable, they just work within this new context:

<xsl:template match="/">
  <xsl:variable name="phase-1-result">
    <xsl:apply-templates select="/" mode="phase-1"/>
  </xsl:variable>

  <TABLE border="1">
    <xsl:apply-templates  mode="phase-2"
      select="($phase-1-result/ListOfLabels/Label)[position() mod 3 = 1]"/>
  </TABLE>
</xsl:template>

<!-- phase-1 template as before -->

<xsl:template match="Label" mode="phase-2">
  <TR>
    <xsl:apply-templates select=".|following-sibling::Label[position() lt 3]"
                         mode="columns" />
  </TR>
</xsl:template>

<xsl:template match="Label" mode="columns">
  <TD>
    <xsl:value-of select="." />
  </TD>
</xsl:template>

Here I'm doing the "select every third Label" logic at the point of applying the phase-2 template, so that template only needs to concern itself with the "me and my next two siblings" bit.

It's no different from declaring a variable containing nodes from the original input tree and then applying templates to those

<xsl:variable name="someNodes" select="/foo/bar | /foo/ping" />
<xsl:apply-templates select="$someNodes" />

<xsl:template match="bar">...</xsl:template>

The template match expressions don't care where the nodes came from, they only care what the nodes look like (is it a bar or a ping).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top