Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old August 17th, 2007, 08:27 AM
Registered User
 
Join Date: Aug 2007
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default XSL multiple files in table (nested for-each ?)

Hi

im a newbie so be kind. I am trying to create a slightly complicated table where the columns represent different xml files. The rows represent the columns of data.

The file being translated is a very simple element which contains a number of report elements that point to different xml files with @file.

I'm reading the first file outputting columns for each weapon name. Within this loop i am trying to loop through each file looking for data about that weapon.

The inner loop never returns any result. Could anyone help explain why

Code:
<xsl:template name='Weapons'>
    <tr>
            <xsl:for-each select="/SeagoingTrimReportSummary/report[1]">
                <xsl:variable name="first_report" select="@file"/>
                <xsl:value-of select="@file"/>
                    <th colspan="1"><xsl:attribute name="rowspan" select="count(sg:weapon)+1"/>Weapons</th>
                    <tr>
                        <xsl:for-each select="sg:weapon">        
                            <xsl:variable name="weapon_type" select="@type"/>
                            <th colspan="1"><xsl:attribute name="rowspan"><xsl:value-of select="count(sg:weapon)+1"/></xsl:attribute><xsl:value-of select="@type"/></th>
                            <tr>
                                <xsl:for-each select="/SeagoingTrimReportSummary/report">
                                    <td><xsl:value-of select="document(@file)/sg:SeagoingTrimReport/sg:weapons_payload/sg:weapon[@type = $weapon_type]/@amount"/></td>
                                </xsl:for-each>
                            </tr>
                        </xsl:for-each>
                    </tr>
                </xsl:for-each>
            </xsl:for-each>
    </tr>
</xsl:template>

 
Old August 17th, 2007, 02:30 PM
Registered User
 
Join Date: Aug 2007
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi sorry. Please ignore the last code segment, this is what i am currently trying.

Reading the first report and within the for-each weapon loop, going in another for-each loop reading data about each weapon type across all files.

(The table is represented with data headings on the left, and columns of data for each report)


<xsl:for-each select="/SeagoingTrimReportSummary/report[1]">
<xsl:for-each select="document($first_report)/sg:SeagoingTrimReport/sg:weapons_payload">
<th colspan="1"><xsl:attribute name="rowspan" select="count(sg:weapon)+1"/>Weapons</th>
    <tr>
        <xsl:for-each select="sg:weapon">
             <xsl:variable name="weapon_type" select="@type"/>
             <th colspan="1"><xsl:attribute name="rowspan"><xsl:value-of select="count(sg:weapon)+1"/></xsl:attribute><xsl:value-of select="@type"/></th>
             <tr>
                 <xsl:for-each select="/SeagoingTrimReportSummary/report">
                     <td><xsl:value-of select="document(@file)/sg:SeagoingTrimReport/sg:weapons_payload/sg:weapon[@type = $weapon_type]/@amount"/></td>
                 </xsl:for-each>
             </tr>
        </xsl:for-each>
     </tr>
</xsl:for-each>

 
Old August 18th, 2007, 11:43 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

It's difficult to debug this for you without seeing the source documents, but this version looks a lot more sane than the previous version.

Are you sure the prefix sg: is used or omitted correctly in all cases?

Quite apart from anything relating to the source document, it's generating invalid HTML: you can't have a <tr> element as a child of another <tr>. I suspect there is a missing td/table.

Your outer xsl:for-each is doing select="document($first_report)/sg:SeagoingTrimReport/sg:weapons_payload".

So, if it selects anything, then it selects a node in a document whose outermost element is called sg:SeagoingTrimReport.

The next for-each does select="sg:weapon", so you are still in the same document.

The next for-each does select="/SeagoingTrimReportSummary/report". We know that the outermost element is called sg:SeagoingTrimReport, so /SeagoingTrimReportSummary can't possibly select anything.


Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old August 19th, 2007, 04:23 AM
Registered User
 
Join Date: Aug 2007
Posts: 3
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi thanks for the reply.

I appreciate its hard to debug especially with the strange html. Ignoring that for a sec i will show you some source.

There are 2 types of file - SeagoingTrimReport and SeagoingTrimReportSummary.

heres an example of the SeagoingTrimReport (which defines the namespace refered to in the summary translation as sg):

Code:
<SeagoingTrimReport>
    <weapons_payload>
        <weapon type="gun" amount="3"/>
        <weapon type="grenade" amount="2"/>
        <weapon type="bomb" amount="1"/>
    </weapons_payload>
<SeagoingTrimReport>
The SeagoingTrimReportSummary is just a list of SeagoingTrimReport docs:

Code:
<SeagoingTrimReportSummary>
    <report file="C:\report1.xml"/>
    <report file="C:\report2.xml"/>
    <report file="C:\report3.xml"/>
</SeagoingTrimReportSummary>
My question is ... how can i output the types of each weapon listed in the first report, and for each of them go through all the other reports writing out the amount in each report.

If i cannot use a for-each in this way then could you help me figure out how this can be done?

Thanks for your help

 
Old August 19th, 2007, 07:06 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

When you're dealing with multiple documents, it's probably best to avoid path expressions starting with "/". Declare a variable bound to each document (e.g. a global variable <xsl:variable name="input" select="/"/> for the initial input document) and then use path expressions of the form $input/a/b/c. Otherwise it's very easy to inadvertently select within the wrong document.

Another tip: avoid using Windows filenames like file="C:\report1.xml" in XML documents. Instead, use URIs: file="file:/c:/report1.xml". The document() function is only defined to work with URIs. Some products allow you to get away with using a Windows filename where a URI is expected, but it's not standard.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old August 21st, 2007, 08:00 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

As Michael says, its all about context.

If you'll pardon the bad namespace declaration this should be something like what you are after.

Code:
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:sg="http://sg">

  <xsl:template match="/">
    <xsl:variable name="context" select="." />
    <html>
      <body>

        <table>
        <xsl:for-each select="/SeagoingTrimReportSummary/report[1]">
            <xsl:variable name="first_report" select="document(@file)" />
            <tr>
                <th><xsl:attribute name="rowspan"><xsl:value-of select="count($first_report//sg:weapon)+1" /></xsl:attribute>Weapons</th>
            </tr>
            <xsl:for-each select="$first_report//sg:weapon">
                <xsl:variable name="type" select="@type" />
                <tr>
                <th><xsl:value-of select="$type" /></th>

                <xsl:for-each select="$context//report">
                    <xsl:variable name="report" select="document(@file)" />
                    <td><xsl:value-of select="$report//sg:weapon[@type = $type]/@amount" /></td>
                </xsl:for-each>
                </tr>
            </xsl:for-each>
        </xsl:for-each>

        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
You'll notice at the top I declared the $context variable, and then when in the inner-most for-each loop I use that again, so replacing your "/SeagoingTripReportSummary/report" with "$context//report". "/SeagoingTripReportSummary/report" wont work as you are effectively 'inside' the "weapon" element of the loaded document.







Similar Threads
Thread Thread Starter Forum Replies Last Post
very urgent:cals table to indesign table using xsl franklinclinton XSLT 1 December 16th, 2009 03:48 PM
Multiple FOP files to single PDF using XSL bhavanimachani XML 7 March 28th, 2008 05:59 AM
Logic builiding with Nested/Multiple IIF rohit_ghosh Access 4 May 4th, 2007 09:52 AM
nested sproc temp table cole SQL Language 1 June 9th, 2005 05:27 PM
Importing Multiple files in Multiple tables Versi Suomi Access 6 June 1st, 2005 08:47 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.