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 January 27th, 2011, 03:43 PM
Friend of Wrox
 
Join Date: May 2004
Posts: 109
Thanks: 18
Thanked 0 Times in 0 Posts
Default XPathing mixed data

I am using Saxon 9, I also use Oxygen 12.1 on a Windows XP machine.

I have some mixed content such as this:
Code:
<AAA>Some Text
   <BBB>
      <CCC>1</CCC>
      <CCC>2</CCC>
   </BBB>
More Text
   <BBB>
      <CCC>3</CCC>
      <CCC>4</CCC>
      <CCC>5</CCC>
    </BBB>
End of Text
</AAA>
At the end of the day, I'm going to turn this into 6 text strings to be sent to other parts of my XSLT scripts.
The lines will look like:

Some Text1More Text3End of Text
Some Text1More Text4End of Text
Some Text1More Text5End of Text
Some Text2More Text3End of Text
Some Text3More Text4End of Text
Some Text3More Text5End of Text

There will be 0 or more BBB element structures and There may or may not be text before, in between or after the BBB nodes.

My thought is to write a recursive template that would take the AAA structure and if there are no BBB structures, just dump the text node.
If there are BBB structures, get the CCC values for one of the BBB structures, say the left most one, and concat the surrounding text with the selected CCC value and any remaining BBB structures and resend to the template. Then when we bounce back to the first recursion, bump the CCC value to the next value, concat with the text and send it through again. Eventually I will have processed all CCC values for all BBB elements and dumped each text string to a temporary result so I can do something with it later.

My problem, except for maybe doing this the most difficult way possible, is that I don't know how to tell what order the text nodes are with the BBB nodes. So, how can I tell that 'Some Text' preceeds a BBB structure and that 'End of Text' succeeds a BBB structure? I can put just the text nodes in order using text()[1], text()[2], or text()[3] and I can put the BBB nodes in order using ./BBB[1] and ./BBB[2], but how do I get the text() and BBB nodes in the right order with each other?

Also, if you know a better way to do this, I'm all ears (or all eyes in this case)

Thanks,

- m
__________________
------------------------
Keep Moving Forward

GnuPG Key fingerprint = 1AD4 726D E359 A31D 05BF ACE5 CA93 7AD5 D8E3 A876

Michael Hare
 
Old January 27th, 2011, 05:17 PM
Friend of Wrox
 
Join Date: May 2004
Posts: 109
Thanks: 18
Thanked 0 Times in 0 Posts
Default

It appears child::node(), self::text() and self::BBB have potential.
__________________
------------------------
Keep Moving Forward

GnuPG Key fingerprint = 1AD4 726D E359 A31D 05BF ACE5 CA93 7AD5 D8E3 A876

Michael Hare
 
Old January 28th, 2011, 05:25 AM
samjudson's Avatar
Friend of Wrox
 
Join Date: Aug 2007
Posts: 2,128
Thanks: 1
Thanked 189 Times in 188 Posts
Default

Well that's certainly not an easy problem to solve.

I've managed to get the following working. It doesn't check for 0 BBB elements - but you could put some simple logic in the AAA template to handle that.

Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">
  
<xsl:output method="text"/>

<xsl:template match="AAA">
	<xsl:apply-templates select="BBB[1]"/>
</xsl:template>

<xsl:template match="BBB">
	<xsl:param name="string"/>
	<xsl:variable name="b" select="."/>
	
	<xsl:for-each select="CCC">
		<xsl:variable name="tmp">
		<xsl:value-of select="normalize-space($b/preceding-sibling::text()[1])"/>
		<xsl:value-of select="normalize-space(.)"/>
		</xsl:variable>
		<xsl:choose>
			<xsl:when test="$b/following-sibling::BBB[1]">
				<xsl:apply-templates select="$b/following-sibling::BBB[1]">
					<xsl:with-param name="string" select="concat($string,string($tmp))"/>
					</xsl:apply-templates>
				</xsl:when>
				<xsl:otherwise>
					<xsl:value-of select="concat($string,$tmp)"/>
					<xsl:value-of select="normalize-space($b/following-sibling::text()[1])"/>
<xsl:text>
</xsl:text>
					</xsl:otherwise>
			</xsl:choose>
	</xsl:for-each>
</xsl:template>

</xsl:stylesheet>
__________________
/- Sam Judson : Wrox Technical Editor -/

Think before you post: What have you tried?
 
Old January 28th, 2011, 11:33 AM
Friend of Wrox
 
Join Date: May 2004
Posts: 109
Thanks: 18
Thanked 0 Times in 0 Posts
Default

Thanks, Sam. I'll look over your code in more detail.

Here's what I have:

Code:
<!--
   =======================================================================
-->
    <xsl:template name="ParseIterator">
        <xsl:param name="myData"></xsl:param>
        
        
        <xsl:if test="empty($myData//BBB)">
            <xsl:text>&#x0a;</xsl:text>
            <xsl:text>No BBB: </xsl:text>
            <xsl:value-of select="$myData"></xsl:value-of>
        </xsl:if>  
        
        <xsl:if test="exists($myData//BBB)">
            <xsl:text>&#x0a;</xsl:text>
            <xsl:text>Yes BBB: </xsl:text>
            
            <xsl:for-each select="$myData//BBB[1]/CCC">
                <xsl:variable name="temp">
                    <xsl:value-of select=" ancestor::BBB/preceding-sibling::node()"></xsl:value-of>
                    <xsl:value-of select="."></xsl:value-of>
                    <!--
                    <xsl:value-of select="ancestor::BBB/following-sibling::node()"></xsl:value-of>
                    -->
                    <xsl:apply-templates select="ancestor::BBB/following-sibling::node()"></xsl:apply-templates>
                </xsl:variable>
                
                <xsl:call-template name="ParseIterator">
                    <xsl:with-param name="myData" select="$temp"></xsl:with-param>
                </xsl:call-template>
                <!--
                <xsl:text>Dump Temp: </xsl:text>
                <xsl:value-of select="$temp"></xsl:value-of>
                <xsl:text>&#x0a;</xsl:text>
                -->
            </xsl:for-each>
            
        </xsl:if>
        
    </xsl:template>
    
    
    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
It's got a lot of the debugging output still included, but it's working.

With this as an input:
Code:
<!--
        =======================================================================
    -->
    <xsl:template match="//ROOT">
        <xsl:text>&#x0a;</xsl:text>
        <xsl:text>Starting...</xsl:text>
        <xsl:text>&#x0a;</xsl:text>
        
        <xsl:variable name="test1">
            <AAA>This is a test string for number 1</AAA>
        </xsl:variable>
        
        <xsl:variable name="test2">
            <AAA>First Text<BBB><CCC>1</CCC><CCC>2</CCC></BBB>Middle Text<BBB><CCC>3</CCC><CCC>4</CCC><CCC>5</CCC></BBB>End Text</AAA>
        </xsl:variable>
        
        <xsl:text>&#x0a;</xsl:text>
        <xsl:text>Test 1: </xsl:text>
        <xsl:call-template name="ParseIterator">
            <xsl:with-param name="myData" select="$test1"></xsl:with-param>
        </xsl:call-template>

        <xsl:text>&#x0a;</xsl:text>
        <xsl:text>Test 2: </xsl:text>
        <xsl:call-template name="ParseIterator">
            <xsl:with-param name="myData" select="$test2"></xsl:with-param>
        </xsl:call-template>
        
        <xsl:text>&#x0a;</xsl:text>

        <xsl:text>...Ending</xsl:text>
        <xsl:text>&#x0a;</xsl:text>
    </xsl:template>
I get this as an output:
Code:
Starting...

Test 1: 
No BBB: This is a test string for number 1
Test 2: 
Yes BBB: 
Yes BBB: 
No BBB: First Text1Middle Text3End Text
No BBB: First Text1Middle Text4End Text
No BBB: First Text1Middle Text5End Text
Yes BBB: 
No BBB: First Text2Middle Text3End Text
No BBB: First Text2Middle Text4End Text
No BBB: First Text2Middle Text5End Text
...Ending
__________________
------------------------
Keep Moving Forward

GnuPG Key fingerprint = 1AD4 726D E359 A31D 05BF ACE5 CA93 7AD5 D8E3 A876

Michael Hare





Similar Threads
Thread Thread Starter Forum Replies Last Post
Mixed content in DTDs GrantRobertson BOOK: Beginning XML, 4th Ed ISBN: 978-0-470-11487-2 0 November 2nd, 2009 12:40 AM
Help transforming mixed complexType davegreig1978 XSLT 2 February 25th, 2009 02:46 PM
mixed content parsing joeri XSLT 2 October 7th, 2007 04:54 PM
Java solution Read Mixed data columns from excel. pranjaldutta VBScript 1 March 19th, 2007 12:29 PM
mixed mode authentication Tremmorkeep SQL Server 2000 6 June 21st, 2004 12:14 PM





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