 |
| 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
|
|
|
|

August 10th, 2006, 09:52 AM
|
|
Registered User
|
|
Join Date: Jul 2006
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Filtering XML data based on differnt XML
I am a beginner in XSLT.
I have an input XML file and a requiredelement.xml file which tells me the name of the elements that should be there in the output.
input.xml
<Root>
<M1>
<Element1>
<Citizenship>aaaaaaaaa</Citizenship>
<Phone a="b">phonenumber</Phone>
<EmailAddress>email</EmailAddress>
</Element1>
<Element2>
<Element2_2>Some data</Element2_2>
</Element2>
<Element3>data3</Element3>
<Element4>data4</Element4>
<Element5>data5</Element5>
<Element6>data6</Element6>
<Element7>data7</Element7>
<Element8>data8</Element8>
<Element9>data9</Element9>
</M1>
</Root>
requiredelemnt.xml
<OutputElements>
<segment>Element1</segment>
<segment>Element6</segment>
</OutputElements>
The desired output
<Root>
<M1>
<Element1>
<Citizenship>aaaaaaaaa</Citizenship>
<Phone a="b">phonenumber</Phone>
<EmailAddress>email</EmailAddress>
</Element1>
<Element6>data6</Element6>
</M1>
</Root>
The XSL I am trying ( I know its wrong, but this as far as I can get )
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:template match="/">
<xsl:for-each select="document('requiredelemnt.xml.xml')//segment">
<xsl:apply-templates select=".">
<xsl:with-param name="segvalue">
<xsl:value-of select="."/>
</xsl:with-param>
</xsl:apply-templates>
Here1
</xsl:for-each>
</xsl:template>
<xsl:template match="segment">
<xsl:param name="segvalue">localvalue</xsl:param>
<xsl:copy-of select="$segvalue"/>
Here 2 .. Value = <xsl:value-of select="$segvalue"/>
</xsl:template>
</xsl:stylesheet>
The actual output that I am getting:
<?xml version="1.0" encoding="UTF-8"?>
Here 2 .. Value = Element1
Here1
Here 2 .. Value = Element6
Here1
Can you please help to correct or point me if I am totally off the mark.
Thanks
|
|

August 10th, 2006, 12:40 PM
|
 |
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
I would tackle this using two template rules: an identity copy rule that matches elements in the main document that are named in the second document, and a pass-through rule that matches elements not so named.
<xsl:template match="*[document('....')/x/y/z = name()]">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
|

August 10th, 2006, 04:22 PM
|
|
Registered User
|
|
Join Date: Jul 2006
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks a lot.. I could build my XSL based on your suggestions. I wanted the root element and its one subelement from the source and then filter based on my requiredelements.xml so here is the XSL
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:output method="xml"/>
<xsl:template match="/*|/*/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="copy"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:strip-space elements="*"/>
<xsl:template match="*[document('v1.xml')//segment = name()] ">
<xsl:copy>
<xsl:copy-of select="@*|node()"/>
<xsl:apply-templates mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
|
|

August 11th, 2006, 08:06 AM
|
|
Registered User
|
|
Join Date: Jul 2006
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks Michael for your previous answer.
Just a small question. In the previous XSL, I am trying to do a case insensitive match by having the following XSL, but I get the error
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xdt="http://www.w3.org/2005/xpath-datatypes">
<xsl:variable name="reqelm" select="document('v1.xml')"/>
<xsl:output method="xml"/>
<xsl:template match="/*|/*/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates mode="copy"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:strip-space elements="*"/>
<xsl:template match="*[lower-case($reqelm//segment)=lower-case(name())] ">
<xsl:copy>
<xsl:copy-of select="@*|node()"/>
<xsl:apply-templates mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
The error is :
XPathParserException: The function 'lower-case' was not found.
pattern = '*[lower-case($reqelm//segment)=lower-case(name())] ' Remaining tokens are: ( 'lower-case' '(' '$' 'reqelm' '/' '/' 'segment' ')' '=' 'lower-case' '(' 'name' '(' ')' ')' ']') (t5.xsl, line 12, column 76)
I tried to replace the lower-case() with matches() but same problem.
|
|

August 11th, 2006, 08:12 AM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Posts: 3,074
Thanks: 1
Thanked 38 Times in 37 Posts
|
|
Which processor are you using, very few support version 2.0, which lower-case() needs?
In version 1.0 you can use translate(string, from, to) and provide the appropriate alphabet strings for the last two parameters. This works with ASCII characters only though.
--
Joe ( Microsoft MVP - XML)
|
|

August 11th, 2006, 09:15 AM
|
|
Registered User
|
|
Join Date: Jul 2006
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Thanks Joe.
I am using Xalan version 1.10.0. so its not XSLT 2 I guess.
However when I tried to use translate in the match, I only get match on the first element
In the above example, I change the match line to
<xsl:template match="*[ translate($reqelm//segment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')=
translate(name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')
] ">
I get the case insensitive match but only first element in ,my output. So the output I am getting now is
<Root>
<M1>
<Element1>
<Citizenship>aaaaaaaaa</Citizenship>
<Phone a="b">phonenumber</Phone>
<EmailAddress>email</EmailAddress>
</Element1>
</M1>
</Root>
The expected output was
<Root>
<M1>
<Element1>
<Citizenship>aaaaaaaaa</Citizenship>
<Phone a="b">phonenumber</Phone>
<EmailAddress>email</EmailAddress>
</Element1>
<Element6>data6</Element6>
</M1>
</Root>
Any clue ?
|
|
 |