简体   繁体   中英

Help with multi-pass XSLT using node-set()

I need to display certain data in a tabular form, and would prefer to use multi-pass xslt using node-set() so that I can avoid deploying additional tools (like xsltproc). Right now, I'm able to perform the required task in two steps ie

Step 1: convert XML-1 to XMl-2 using identity template (xsl:copy, using xsl:element to add dynamic elements 'dev' and 'qa`):

<projectteam>
  <member>
    <name>John</name>
    <role>dev</role>
    <hrs>100</hrs>
  </member>
  <member>
    <name>Peter</name>
    <role>qa</role>
    <hrs>80</hrs>
  </member>
</projectteam>

To

<projectteam>
  <member>
    <name>John</name>
    <dev>100</dev>
  </member>
  <member>
    <name>Peter</name>
    <qa>80</qa>
  </member>
<projectteam>

And then, use another XSLT-FO style sheet to transform XML #2 into a PDF document with the required layout:

name | dev | qa |
-----------------
John | 100 |    |
Peter|     | 80 |
-----------------
Total| 100 | 80 |

I've tried using node-set() (incorrectly I suppose) to combine both the steps, but it wouldn't work as the result I get is as follows:

name | dev | qa |
-----------------
Total|  0  |  0 |

Stylesheet-1: converts XML-1 to XML-2, imports another stylesheet 'projDisplay.xsl', uses node-set() to invoke the imported stylesheet, but the data doesn't get displayed?

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format"
  xmlns:exslt="http://exslt.org/common"
>

  <!-- import stylesheet to display XML-2 in tabular form -->
  <xsl:import href="projDisplay.xsl"/>

  <xsl:template match="/">
    <fo:root>
      <xsl:apply-templates/>
    </fo:root>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:variable name="newXmlData">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:variable>

    <!-- ==> This is where my problem is - it goes to the template defined in  -->
    <!-- projDisplay.xsl (xslt-fo, pretty big one with page layout etc. hence  -->
    <!-- not included here, but it works on its own though) as I can see the   -->
    <!-- table header, and an empty totals row, but non of the rows are displayed -->

    <xsl:apply-templates 
      select="exslt:node-set($newXmlData)/projectteam" mode="display"
    />
  </xsl:template>

  <!-- replace element 'role' with a new element - role name (i.e. dev or qa) -->
  <!-- and set its value as 'hrs                                              -->
  <xsl:template match="role">
    <xsl:element name="{.}"> <xsl:value-of select="../hrs"/> </xsl:element>
  </xsl:template>

  <!-- eliminate element 'hrs' -->
  <xsl:template match="hrs"/>
</xsl:stylesheet>

The commented section in the stylesheet doesn't look right to me. Any suggestions about how to correct it?

Thanks!

Here's the solution that works. It's based on Tomalak's original solution with some minor modifications (like mode flags etc.) Again, thanks to Tomalak!!

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exslt="http://exslt.org/common"
  version="1.0">

 <xsl:import href="projDisplay.xsl"/>

 <xsl:template match="/">
  <!-- store intermediate form as RTF -->
  <xsl:variable name="newXmlData">
   <xsl:apply-templates mode="filter"/>
  </xsl:variable>

  <!-- Now apply templates (with xslt-fo) defined in projDisplay.xsl with     -->
  <!-- the root template as <xsl:template match="projectteam" mode="display"> -->
  <!-- to the above RTF (i.e. after the original XML has be convertedr)       -->
  <xsl:apply-templates select="exslt:node-set($newXmlData)/projectteam" mode="display"/>

 </xsl:template>

 <!-- use identity templates to copy and modify original XML -->
 <xsl:template match="@*|node()" mode="filter">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()" mode="filter"/>
  </xsl:copy>
  </xsl:template>

 <!-- replace element 'role' with a new element - role name (i.e. dev or qa) -->
 <!-- and set its value as 'hrs                                              -->
 <xsl:template match="member/role" mode="filter">
  <xsl:element name="{.}"> <xsl:value-of select="../hrs"/> </xsl:element>
 </xsl:template>

 <!-- eliminate element 'hrs' -->
 <xsl:template match="hrs" mode="filter"/>

</xsl:stylesheet>

What about:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:fo="http://www.w3.org/1999/XSL/Format"
  xmlns:exslt="http://exslt.org/common"
  exclude-result-prefixes="exslt"
>

  <xsl:import href="projDisplay.xsl"/>

  <xsl:template match="/">
    <!-- store intermediary format as a RTF -->
    <xsl:variable name="newXmlData">
      <xsl:apply-templates />
    </xsl:variable>
    <!-- now we can the apply imported rules -->
    <xsl:apply-templates 
      select="exslt:node-set($newXmlData)/projectteam"
      mode="import"
    />
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="member/role">
    <xsl:element name="{.}">
      <xsl:value-of select="../hrs" />
    </xsl:element>
  </xsl:template>

  <xsl:template match="member/*" />

  <xsl:template match="projectteam" mode="import">
    <fo:root>
      <xsl:apply-imports />
    </fo:root>
  </xsl:template>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM