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 December 13th, 2012, 06:23 AM
Authorized User
 
Join Date: Sep 2012
Posts: 35
Thanks: 18
Thanked 0 Times in 0 Posts
Default Extract string by position()

Hello,

Rather than clutter my template with lots of xsl:if statements I thought it would make sense to create a for-each loop. However, running this code
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <xsl:param name="target" as="xs:anyURI" required="no"/>
    <xsl:param name="types" as="xs:integer" required="no" select="5"/>
    <xsl:variable name="root"><doc/></xsl:variable>

    <xsl:template name="build">
        <xsl:variable name="modes" select="tokenize('CSV XML HTML', ',')" as="xs:string+"/>
        <xsl:for-each select="(1,2,4)">
            <xsl:message select="'Mode : ', $modes[position()]"/>
            <xsl:if test="(floor($types  div .) mod 2 = 1)">
                <!-- <xsl:apply-templates select="$root" mode="xs:QName({$modes[position()]})"/> -->
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    
    <!-- Generate CSV Output -->
    <xsl:template match="/" mode="CSV">
        <xsl:comment>CSV Builder Template</xsl:comment>
    </xsl:template>
    <!-- Generate XML Output -->
    <xsl:template match="/" mode="XML">
        <xsl:comment>XML Builder Template</xsl:comment>
    </xsl:template>
    <!-- Generate HTML Output -->
    <xsl:template match="/" mode="HTML">
        <xsl:comment>HTML Builder Template</xsl:comment>
    </xsl:template>
    
</xsl:stylesheet>
I get :
Code:
Mode :  CSV XML HTML
Mode :  CSV XML HTML
Mode :  CSV XML HTML
and not
Code:
Mode : CSV
Mode : XML
Mode : HTML
As I had hoped. As a consequence of this my mode=xs:QName({$modes[position()]}) generates an error, hence the comments on it. Can this attribute even be made dynamic?

I have tried lots of variations of this approach but I end up with a similar result. Could someone maybe tell me what / where I am going wrong?

--
William
 
Old December 13th, 2012, 06:53 PM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

An integer predicate E[N] means, by definition, E[position()=N]. So E[position()] means E[position()=position()]; the predicate is therefore always true.

Bind a variable to position() first:

<xsl:variable name="p" select="position()"/>

and then use E[$p]
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
The Following User Says Thank You to mhkay For This Useful Post:
WilliamYou (December 14th, 2012)
 
Old December 14th, 2012, 04:44 AM
Authorized User
 
Join Date: Sep 2012
Posts: 35
Thanks: 18
Thanked 0 Times in 0 Posts
Default

Thank you once again Mr. Kay. I have re-worked the build template to include your solution
Code:
<xsl:template name="build">
        <xsl:variable name="modes" select="(xs:QName('CSV'), xs:QName('XML'), xs:QName('HTML'))" as="xs:QName+"/>
        <xsl:for-each select="(1, 2, 4)">
            <xsl:variable name="pos" select="position()"/>
            <xsl:variable name="mode" select="$modes[$pos]" as="xs:QName"/>
            <xsl:if test="(floor($types  div .) mod 2 = 1)">
                <xsl:message select="'Selected format : ', $mode"/>
                <xsl:apply-templates select="$root" mode="{$mode}"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
and when applicable I get an xsl:message to the console listing my selection. However, I am still unable to make the mode attribute of the xsl:apply-templates dynamic using this approach. Is it even possible?

I have tried various options here but regardless Oxygen (Saxon-PE 9.4.0.4) tells me that the value used is not a valid QName, so I am beginning to think that this approach simply will not work.

I know it's not the end of the world but it is my preferred solution and I would have liked to have had it working.

Can anyone tell me if making this attribute's value dynamic is possible?

--
William
 
Old December 14th, 2012, 10:44 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

No, it's not possible to make the mode dynamic. Sorry I didn't look more closely at your code and only addressed the most immediate problem.

One possibility is to do

Code:
<xsl:variable name="formats" as="element()*>
  <CSV/>
  <HTML/>
  <XML/>
</xsl:variable>
and then

Code:
<xsl:apply-templates select="$formats[$p]">
   <xsl:with-param name="root" select="$root"/>
</xsl:apply-templates>

<xsl:template match="CSV">
  <xsl:param name="root"/>
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
The Following User Says Thank You to mhkay For This Useful Post:
WilliamYou (December 14th, 2012)
 
Old December 14th, 2012, 11:21 AM
Authorized User
 
Join Date: Sep 2012
Posts: 35
Thanks: 18
Thanked 0 Times in 0 Posts
Default

Thank you again Mr. Kay, very much appreciated.

For those that are interested here is the final template (prior to filling in the blanks of course).

Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
    <!-- The path and name of the output without an extension -->
    <xsl:param name="target" as="xs:anyURI" required="yes"/>
    <!-- The value of the mask of the template(s) you want to apply -->
    <xsl:param name="types" as="xs:integer" required="yes"/>
    <xsl:variable name="root"><doc/></xsl:variable>
    <xsl:variable name="formats" as="element()*"><CSV/> <HTML/> <XML/> <SQL/></xsl:variable>
    <xsl:template name="build">
        <xsl:for-each select="(1, 2, 4, 8)">
            <xsl:variable name="pos" select="position()"/>
            <xsl:if test="(floor($types  div .) mod 2 = 1)">
                <xsl:apply-templates select="$formats[$pos]">
                    <xsl:with-param name="root" select="$root"/>
                </xsl:apply-templates>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
    
    <!-- Generate CSV Output -->
    <xsl:template match="CSV">
        <xsl:param name="root"/>
        <xsl:variable name="csvResults" select="concat($target, '.csv')"/>
        <xsl:result-document href="{$csvResults}" method="text" omit-xml-declaration="yes">
            <!-- CSV output code here -->
        </xsl:result-document>
    </xsl:template>
    
    <!-- XML template here. -->
    <!-- SQL template here. -->
    <!-- HTML template here. -->
    <!-- Other templates here ... -->

</xsl:stylesheet>
I hope it's of use to someone.

--
William

Last edited by WilliamYou; December 14th, 2012 at 11:42 AM..





Similar Threads
Thread Thread Starter Forum Replies Last Post
Extract a digit from specified position sektor Visual Basic 2005 Basics 10 June 9th, 2008 05:05 PM
Extract part of String carrie09 Access 6 August 24th, 2007 10:04 AM
Extract first numeric string blkskullwork Javascript 1 November 6th, 2006 02:37 AM
how to extract from a string fraijo SQL Server 2000 3 October 25th, 2006 09:55 PM
How to extract a substring from a string.... muralish MySQL 2 May 18th, 2005 06:58 AM





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