[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

sort a node across a dynamic group of files

Subject: sort a node across a dynamic group of files
From: J. Argyl Plath <jargylplath@xxxxxxxxx>
Date: Sun, 22 Nov 2009 14:28:14 -0500
 sort a node across a dynamic group of files
Hello--

I searched the archives of this forum (and the internet at large) looking for
an answer to this query before posting, but I apologize in advance if I missed
something. I found lots of results that seem to work if you have a static (and
known) list of files before starting. If you have any suggestions for better
search terms, please let me know.

I am using XSLT 1.0. I perform the transformation using PHP 5.3.0 / Xalan
2.4.1 on an Apache 2.2.13 server. Unfortunately I do not have admin access to
Apache to do any kind of upgrades that would allow me to use XSLT 2.0.

Here's more context than you could ever want:

I have multiple XML files in a directory. The number of files is frequently
growing but they are all named ####.xml (example: 0001.xml, 0002.xml,
0003.xml, etc.) It is important to know that there will *never* be any skipped
numbers. If 0100.xml exists it is guaranteed that 0001-0099 exist as well.

The relevant structure of these files is as follows:

	<!-- Entry XML -->
	<xs:element name="entry">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="id" />
				<xs:choice>
					<xs:group ref="name" />
					<xs:element ref="name" />
				</xs:choice>
				[ ... ]
			</xs:sequence>
		</xs:complexType>
	</xs:element>

And the elements / group referenced:

	<!-- Elements -->
	<xs:element name="firstName" type="xs:token" />
	<xs:element name="id" type="xs:integer" />
	<xs:element name="lastName" type="xs:token" />
	<xs:element name="middleName" type="xs:token" />
	<xs:element name="name" type="xs:token" />

	<!-- Groups -->
	<xs:group name="name">
		<xs:sequence>
			<xs:element ref="firstName" />
			<xs:element ref="middleName" minOccurs="0" maxOccurs="unbounded" />
			<xs:element ref="lastName" minOccurs="0" />
		</xs:sequence>
	</xs:group>

There are never more than one entry in a given file. I use a schema to
validate that this is true. I keep track of how many entry files there are
through a PHP script that runs periodically and updates a master XML file with
the current count of entry XML files.

The relevant structure of this master XML file is as follows:

	<!-- TOC XML -->
	<xs:element name="toc">
		<xs:complexType>
			<xs:sequence>
				[...]
				<xs:element ref="entries" />
			</xs:sequence>
		</xs:complexType>
	</xs:element>

And the relevant element definition:

	<!-- Elements -->
	<xs:element name="entries" type="xs:integer" />

I have found elsewhere a method where I can dynamically include any number of
files using recursive calls to the same template:

	<!-- Method -->
	<xsl:template match="example">

		<!-- Set up our iterators -->
		<xsl:param name="i" select="document( 'toc.xml' )//entries" />

		<!-- Loop through the matches -->
		<xsl:for-each select="document( concat( format-number( $i, '0000' ), '.xml'
) )">

			<!-- Whatever XSLT work I need done -->

		</xsl:for-each>

		<!-- If there are still items to loop through execute another iteration -->
		<xsl:if test="$i &gt; 1">

			<!-- Apply the template again -->
			<xsl:apply-templates select=".">
				<xsl:with-param name="i" select="$i - 1" />
			</xsl:apply-templates>

		</xsl:if>

	</xsl:template>

And this has worked great for me for other tasks. However, when I need to sort
the items I'm pulling from the external XML files this doesn't seem to work.

I get returned the proper information but in the exact order of the files
(0001 then 0002 then 0003 then 0004) regardless of the sort request.

The reason I use separate XML files and not one big XML file with all the
entries in them is because when you click through the TOC to an entry you only
view one at a time. I cannot use $_REQUEST parameters to specify which record
to display due to the restrictions of my server set-up. All explanations I've
seen that detail how to start using $_REQUEST parameters in your XSLT require
additional installations that I do not have and my inability to edit/access my
apache server prevents me from installing them. So for me to only display
record #5 I have to store the records separately and then pull up 0005.xml and
process it.

Here is an example of the TOC XML file:

	<?xml version="1.0" encoding="utf-8" ?>
	<toc>
		[...]
		<entries>15</entries>
	</toc>

And a couple of examples of the entry XML files:

	<!-- 0001.xml -->
	<?xml version="1.0" encoding="utf-8" ?>
	<entry>
		<id>1</id>
		<firstName>First</firstName>
		<lastName>Last</lastName>
		[...]
	</entry>

	<!-- 0002.xml -->
	<?xml version="1.0" encoding="utf-8" ?>
	<entry>
		<id>2</id>
		<name>Name of Place</name>
		[...]
	</entry>

So. Now that you have lots of context. A direct summary of my problem:

1) The only way I can seem to get and sort all the information is if I
hardcode in variables for every external file and then do a massive for-each
across them. This is highly undesirable because the number of entry XML files
is assumed to soon be in the thousands. I know that I can modify the PHP
script that updates the "entries" section of the TOC XML to also add lines to
the XSL file but I figure there has to be a more efficient way to do this.

Here's the current version of the XSL file I have for this process:

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

		<!-- Set our XHTML 1.0 Strict doctype with no indenting -->
		<xsl:output method="xml" indent="no"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" />

		[...]

		<!-- Table of Contents -->
		<xsl:template match="toc">

			[...]

			<!-- The links -->
			<xsl:element name="ul">
				<xsl:apply-templates select="entries" />
			</xsl:element>

		</xsl:template>

		<!-- Entries -->
		<xsl:template match="entries">

			<!-- Variables -->
			<xsl:variable name="v1" select="document( '0001.xml' )//entry" />
			<xsl:variable name="v2" select="document( '0002.xml' )//entry" />
			<xsl:variable name="v3" select="document( '0003.xml' )//entry" />
			<xsl:variable name="v4" select="document( '0004.xml' )//entry" />

			<!-- and so on -->

			<!-- Loop through the variables -->
			<xsl:for-each select="$v1|$v2|$v3|$v4"> <!-- and so on -->

				<!-- Sort -->
				<xsl:sort select="name|firstName" />

				<!-- The list item -->
				<xsl:element name="li">

					<!-- My XSL processing -->

				</xsl:element>

			</xsl:for-each>

		</xsl:template>

	</xsl:stylesheet>

This actually works. But as I said earlier, maintaining this looks to be a
bear.

An earlier plan was to try and use the recursive method above. That looked
like this:

	<!-- Just the relevant entry template -->
	<xsl:template match="entries">

		<!-- Set up our iterators -->
		<xsl:param name="i" select="document( 'toc.xml' )//entries" />

		<!-- Loop through the matches -->
		<xsl:for-each select="document( concat( format-number( $i, '0000' ), '.xml'
) )">

			<!-- Sort -->
			<xsl:sort select="name|firstName" />

			<!-- The list item -->
			<xsl:element name="li">

				<!-- My XSL processing -->

			</xsl:element>

		</xsl:for-each>

		<!-- If there are still items to loop through execute another iteration -->
		<xsl:if test="$i &gt; 1">

			<!-- Apply the template again -->
			<xsl:apply-templates select=".">
				<xsl:with-param name="i" select="$i - 1" />
			</xsl:apply-templates>

		</xsl:if>

	</xsl:template>

But this failed. It just showed them in the same order that they exist in the
files.

Thank you for any help you can give on this matter. I appreciate any and all
leads. I hope I haven't left any relevant information out.

Cheers,
-J

--
J. Argyl Plath
:-{)
I'm wearing a moustache to help fight prostate cancer.
Learn more and help out at:
http://us.movember.com/mospace/24373

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.