Subject: RE: Sort XML based on Tokenized String of sort by fields
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Thu, 22 May 2008 10:24:24 +0100
|
As David suggests, I think I'd go for the approach of generating a
stylesheet. In effect your <REPORT_FORMAT> element defines a miniature
programming language, and a good way of implementing such languages is often
to translate them to XSLT. I've done similar things with report
specifications entered interactively on the screen. You're already doing
dynamic construction/evaluation of XPath expressions, so dynamic
construction of the entire stylesheet (or of the controlling framework, it
can always include/import a fixed module) isn't a major step from that.
Michael Kay
http://www.saxonica.com/
> -----Original Message-----
> From: Rebecca Sapir [mailto:rsapir@xxxxxxxxxxxxxxxxxxxx]
> Sent: 22 May 2008 00:21
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: Sort XML based on Tokenized String of sort by fields
>
> I am also using the SAXON parser.
> XSLT version 2
>
> I am trying to sort by a tokenized string. I get an ORDER_BY
> string with field names to sort by which are separated by commas.
>
> The number of fields in the order_by string names can vary!!!
>
> The X and X_ROW names are not constant. They can vary and are
> therefore passed in the PARENT_NODE and CHILD_NODE fields.
> For example:
>
> The XML I get is formatted as
>
> <REPORT>
> <REPORT_HDR>
> ...
> </REPORT_HDR>
> <REPORT_FORMAT>
> <ORDER_BY> DATE, ID_1, ID_2, TYPE</ORDER_BY>
> <PARENT_NODE>X</PARENT_NODE>
> <CHILD_NODE>X_ROW</CHILD_NODE>
> </REPORT_FORMAT>
> <X>
> <X_ROW>
> <DATE></DATE>
> <ID_1></ID_1>
> <TYPE ></TYPE>
> ...
> </X_ROW>
> <X_ROW>
> <DATE></DATE>
> <ID_1></ID_1>
> <TYPE ></TYPE>
> ...
> </X_ROW>
> <X_ROW>
> <DATE></DATE>
> <ID_1></ID_1>
> <TYPE ></TYPE>
> ...
> </X_ROW>
> <X_ROW>
> <DATE></DATE>
> <ID_1></ID_1>
> <TYPE ></TYPE>
> ...
> </X_ROW>
> </REPORT>
>
> In this case I want to sort the X/X_ROW's by DATE then ID_1
> then ID_2 etc
>
> This is one solution I have so far...
> (The other one is below which uses recursion instead of tokenize)
>
> <xsl:stylesheet
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="2.0" xmlns:saxon="http://saxon.sf.net/">
> <xsl:variable name="PATH"
> select="REPORT/REPORT_FORMAT/PARENT_NODE" /> <xsl:variable
> name="CHILD" select="REPORT/REPORT_FORMAT/CHILD_NODE" />
> <xsl:variable name="ORDER_BY" select="REPORT/REPORT_FORMAT/ORDER_BY"/>
> <xsl:variable name="ORDER_BY_TOKEN" select="tokenize($ORDER_BY,',')"/>
>
> <xsl:template match="REPORT/*">
>
> <xsl:choose>
>
> <xsl:when test="local-name() = $PATH">
>
> <xsl:copy>
>
> <xsl:for-each select="*">
> <xsl:sort
> select="saxon:evaluate(normalize-space($ORDER_BY_TOKEN[1]))"/>
>
> <xsl:sort
> select="saxon:evaluate(normalize-space($ORDER_BY_TOKEN[2]))"/>
>
> <xsl:sort
> select="saxon:evaluate(normalize-space($ORDER_BY_TOKEN[3]))"/>
>
> <xsl:sort
> select="saxon:evaluate(normalize-space($ORDER_BY_TOKEN[4]))"/>
>
> <xsl:copy-of select="."/>
>
> </xsl:for-each>
>
> </xsl:copy>
>
> </xsl:when>
>
> <xsl:otherwise>
>
> <xsl:copy-of select="."/>
>
> </xsl:otherwise>
>
> </xsl:choose>
>
> </xsl:template>
>
> <xsl:template match="*">
>
> <xsl:copy>
> <xsl:apply-templates/>
> </xsl:copy>
>
> </xsl:template>
>
> </xsl:stylesheet>
>
> My issue of course is that I am hard coding the
> ORDER_BY_TOKEN item that I want. In truth there are a
> variable number of fields that can get passed to me.
>
> Ideally if I could surround the sorts with a for loop that
> would be what I am looking for. But this does not work:
> <xsl:for-each select="*">
>
> <xsl:for-each select="1 to count($ORDER_BY_TOKEN)">
> <xsl:sort
> select="saxon:evaluate(normalize-space($ORDER_BY_TOKEN[.]))"/>
> <xsl:copy-of select="."/>
> </xsl:for-each>
>
> </xsl:for-each>
>
>
> Instead of tokenizing I tried a recursive function. This will
> perform the sorts but not consecutively. So in effect the
> last sort is really the only one that gets applied. Ie. it
> does not have the effect of sort by Date then id_1 then id_2 then...
>
> <xsl:stylesheet
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="2.0" xmlns:saxon="http://saxon.sf.net/">
>
> <xsl:variable name="PATH"
> select="REPORT/REPORT_FORMAT/PARENT_NODE" /> <xsl:variable
> name="ORDER_BY" select="REPORT/REPORT_FORMAT/ORDER_BY"/>
>
>
> <xsl:template match="REPORT/*">
>
> <xsl:choose>
>
> <xsl:when test="local-name() = $PATH">
>
> <xsl:copy>
>
> <xsl:call-template name="tokenize">
> <xsl:with-param name="string" select="$ORDER_BY" />
> </xsl:call-template>
>
> </xsl:copy>
>
> </xsl:when>
>
> <xsl:otherwise>
> <xsl:copy-of select="."/>
> </xsl:otherwise>
>
> </xsl:choose>
> </xsl:template>
>
> <xsl:template match="*">
> <xsl:copy>
> <xsl:apply-templates/>
> </xsl:copy>
> </xsl:template>
>
> <xsl:template name="tokenize">
>
> <xsl:param name="string" />
>
> <xsl:choose>
>
> <xsl:when test="contains($string, ',')">
>
> <xsl:apply-templates>
> <xsl:sort
> select="saxon:evaluate(normalize-space(substring-before($strin
> g,',')))"/>
> </xsl:apply-templates>
>
> <xsl:call-template name="tokenize">
> <xsl:with-param name="string"
> select="substring-after($string, ',')" />
> </xsl:call-template>
>
> </xsl:when>
>
> <xsl:otherwise>
> <xsl:copy>
>
> <xsl:apply-templates>
> <xsl:sort
> select="saxon:evaluate(normalize-space($string))"/>
> </xsl:apply-templates>
>
> <xsl:copy-of select="."/>
> </xsl:copy>
> </xsl:otherwise>
>
> </xsl:choose>
>
> </xsl:template>
>
> </xsl:stylesheet>
>
> Any help would be greatly appreciated.
>
> Thanks.
>
>
>
>
>
>
> Merlin Securities - #1 Prime Broker North America and #1
> Prime Broker Single Strategy Funds - Global Custodian 2007
> #1 Prime Broker for Hedge Funds under $1 Billion - Alpha Survey 2007
>
>
>
>
> --------------------------------------------------------------
> ------------
> This message contains information from Merlin Securities,
> LLC, or from one of its affiliates, that may be confidential
> and privileged. If you are not an intended recipient, please
> refrain from any disclosure, copying, distribution or use of
> this information and note that such actions are prohibited.
> If you have received this transmission in error, please
> notify the sender immediately by telephone or by replying to
> this transmission.
>
> Merlin Securities, LLC is a registered broker-dealer.
> Services offered through Merlin Securities, LLC are not
> insured by the FDIC or any other Federal Government Agency,
> are not deposits of or guaranteed by Merlin Securities, LLC
> and may lose value. Nothing in this communication shall
> constitute a solicitation or recommendation to buy or sell a
> particular security.
|