Hi Simon,
Okay, cool.
I'm going to break the problem into two pieces and discuss them separately.
This is because I think you have two problems, one you asked about, and one
which you've made some indications of (my questions of yesterday), but
which remains underspecified.
The second problem is "how do I transform an arbitrary RNG schema to get
the ("author-implied") order of elements allowed as children of a given
element". Not only is this a tricky question in the general case, but it's
also possible to stipulate you've got a solution. So let's jump ahead and
say you've already transformed your schema, boiling it down to a
representation of your desired order. Given source like yours:
<element name="contact">
<zeroOrMore>
<choice>
<element name="phone">
<optional>
<attribute name="location">
<choice>
<value>
home
</value>
<value>
work
</value>
<value>
mobile
</value>
</choice>
</attribute>
</optional>
<text />
</element>
<element name="fax">
<optional>
<attribute name="location">
<choice>
<value>
home
</value>
<value>
work
</value>
</choice>
</attribute>
</optional>
<text />
</element>
<element name="pager">
<text />
</element>
<element name="email">
<text />
</element>
<element name="url">
<text />
</element>
<element name="instantMessage">
<optional>
<attribute name="service" />
</optional>
<text />
</element>
</choice>
</zeroOrMore>
</element>
Let's say you can transform this to represent the order you want as:
<elementdecl name="contact">
<element name="phone"/>
<element name="fax"/>
<element name="pager"/>
<element name="email"/>
<element name="url"/>
<element name="instantMessage"/>
</elementdecl>
(This transform shouldn't be too hard to write, eh?)
The reason to reconceive the problem this way is that by dumping everything
the schema says about what's optional, wrapped in <zeroOrMore>, etc. etc.,
we simplify down to just what we need, namely the order we want these
elements are to appear in, assuming they appear. (Note we're not interested
in validating anything, only in knowing how to rearrange things.)
Let's name this XML "elementorder.xml".
Your source looks like:
<contact>
<url>http://www.simonwoodside.com/<url>
<email>sbwoodside(_at_)yahoo(_dot_)com</email>
<phone location="work">555-1212</phone>
<fax>555-1111</fax>
</contact>
And what you want to do:
<xsl:template match="*">
<xsl:variable name="thisNode" select="."/>
<!-- we'll need our matched node after we change context -->
<xsl:variable name="orderNode"
select="document('elementorder.xml')//elementdecl[(_at_)name=local-name(current())]"/>
<!-- this variable is a convenience for clarity: finds the node
corresponding to the
declaration of thisNode (the same as current(), here) -->
<xsl:for-each select="$orderNode/*">
<!-- we iterate over the child elements declared for $orderNode -->
<xsl:variable name="orderedNode" select="."/>
<!-- the child is bound to another variable -->
<xsl:copy-of select="$thisNode/*[local-name()=$orderedNode/@name]"/>
<!-- into our result we copy all the children of $thisNode whose name
equals the @name on $orderedNode -->
</xsl:for-each>
</xsl:template>
I hope that's enough to get across the idea. Basically we're using the
document order of the lookup table (the boiled-down schema) to drive the
ordering of the nodes copied into the result. The variables allow us access
to the nodes in both source trees as we change context.
Good luck!
Wendell
___&&__&_&___&_&__&&&__&_&__&__&&____&&_&___&__&_&&_____&__&__&&_____&_&&_
"Thus I make my own use of the telegraph, without consulting
the directors, like the sparrows, which I perceive use it
extensively for a perch." -- Thoreau
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list