ASP/XML/XSL Sorting Problem

W

westguard

Hi

I am trying to get XML data from Facebook sorted, i.e. A-Z! The FQL
from Facebook does not allow you to sort the output, therefore I am
trying to use XSL to sort the XML data before doing anything with it.
I am retrieving the XML using an ASP (Not .Net) script, which works
fine. I am then trying to transform the XML using XSL to sort the data
A-Z. I basically want to list a users friend list alphabetically A-Z.

What seems to be throwing it is this line in the XML:

<fql_query_response xmlns="http://api.facebook.com/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema_instance" list="true">

If I change this (and the closing tag) to <data> or something else
without the attributes, my code works fine, but I need it to work with
the fql_query_response tag - I don't want to mess with the XML before
applying the XSL. I suspect the namespace references is what is
confusing me.

Here is my code so far (this is by no means final, it just represents
how far my 'hacking' has come so far!):

**** XML (Sample - This is fixed from Facebook and cannot be
changed)****
<?xml version="1.0" encoding="ISO-8859-1"?>
<fql_query_response xmlns="http://api.facebook.com/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema_instance" list="true">
<user>
<uid>12345</uid>
<first_name>Joe</first_name>
<last_name>Bloggs</last_name>
</user>
<user>
.... etc
</user>
</fql_query_response>


**** XSL (Something like this) ****
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
Transform">

<xsl:template match="/">

<xsl:for-each select="user">

<xsl:sort select="first_name"/>

<user>
<uid><xsl:value-of select="uid"/></uid>
<first_name><xsl:value-of select="first_name"/></first_name>
<last_name><xsl:value-of select="last_name"/></last_name>
</user>

</xsl:for-each>

</xsl:template>

</xsl:stylesheet>


**** ASP Script (Extract) ****
Dim oXML
Set oXML = Server.CreateObject("Microsoft.XMLDOM")
oXML.async = false
oXML.load(Server.MapPath("/facebook/test.xml"))

Dim oXSL
Set oXSL = Server.CreateObject("Microsoft.XMLDOM")
oXSL.async = false
oXSL.load(Server.MapPath("/facebook/test.xsl"))

response.Write(oXML.transformNode(oXSL))


Note that I am loading the XML and XSL files in manually at the moment
and both report no problems when loading. I've even tried really
simple XSL stuff on the <user> nodes but it just won't pick that up.

How do I referencce the <user> nodes the XSL in order that it is
picked up and processed by tranformNode? I've tried so many different
XSL variations and have not had any luck.

Any feedback or suggestions would be greatly appreciated and I
apologize in advance if I am doing something completely silly! :)

Mark
 
G

George Bina

Hi Mark,

This is a common issue people run into with XSLT/XPath 1.0. If you
have elements in a namespace in your source document then in your
stylesheet you need to define that namespace mapped to a prefix and
then use names qualified with that prefix to match the elements in
that namespace. Not qualified element names will match elements from
no namespace no matter what namespace you define eventually as default
namespace.

For instance your stylesheet should be changed as below:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
Transform"
xmlns:f="http://api.facebook.com/1.0/" >

<xsl:template match="/">

<xsl:for-each select="f:fql_query_response/f:user">

<xsl:sort select="f:first_name"/>

<user>
<uid><xsl:value-of select="uid"/></uid>
<first_name><xsl:value-of select="f:first_name"/></first_name>
<last_name><xsl:value-of select="f:last_name"/></last_name>
</user>

</xsl:for-each>

</xsl:template>

</xsl:stylesheet>

Note that your stylesheet will output elements in no namespace, if you
want to output elements in the http://api.facebook.com/1.0/ namespace
then you should change user to f:user, etc. or define the
http://api.facebook.com/1.0/ as default namespace in your stylesheet.

Best Regards,
George
 
W

westguard

Hi Mark,

This is a common issue people run into with XSLT/XPath 1.0. If you
have elements in a namespace in your source document then in your
stylesheet you need to define that namespace mapped to a prefix and
then use names qualified with that prefix to match the elements in
that namespace. Not qualified element names will match elements from
no namespace no matter what namespace you define eventually as default
namespace.

For instance your stylesheet should be changed as below:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
Transform"
xmlns:f="http://api.facebook.com/1.0/" >

<xsl:template match="/">

<xsl:for-each select="f:fql_query_response/f:user">

<xsl:sort select="f:first_name"/>

<user>
<uid><xsl:value-of select="uid"/></uid>
<first_name><xsl:value-of select="f:first_name"/></first_name>
<last_name><xsl:value-of select="f:last_name"/></last_name>
</user>

</xsl:for-each>

</xsl:template>

</xsl:stylesheet>

Note that your stylesheet will output elements in no namespace, if you
want to output elements in thehttp://api.facebook.com/1.0/namespace
then you should change user to f:user, etc. or define thehttp://api.facebook.com/1.0/as default namespace in your stylesheet.

Best Regards,
George

Hi George

Thank you so much. I made a few tweaks my code and that works
perfectly! I dabbled with inserting the Facebook namespace in the XSL
but didn't quite get there!

My final XSL with your help was as follows (virtually the same, I
added f: to the uid value-of line):


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
Transform" xmlns:f="http://api.facebook.com/1.0/" >

<xsl:template match="/">
<fql_query_response xmlns="http://api.facebook.com/1.0/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema_instance" list="true">

<xsl:for-each select="f:fql_query_response/f:user">

<xsl:sort select="f:first_name"/>

<user>
<uid><xsl:value-of select="f:uid"/></uid>
<first_name><xsl:value-of select="f:first_name"/></first_name>
<last_name><xsl:value-of select="f:last_name"/></last_name>
</user>

</xsl:for-each>

</fql_query_response>
</xsl:template>

</xsl:stylesheet>


I appreciate your thorough response.

Kindest regards

Mark
 
G

George Bina

Hi Mark,

The last stylesheet you posted generates the elements in the
http://api.facebook.com/1.0/ namespace because that is declared as
default namespace in the result root element. One thing that you can
add to that is exclude-result-prefixes="f" to remove the unused
declaration of the http://api.facebook.com/1.0/ namespace bound to the
prefix f, like below:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/
Transform"
xmlns:f="http://api.facebook.com/1.0/" exclude-result-prefixes="f">
....

Best Regards,
George
---------------------------------------------------------------------
George Cristian Bina
<oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger
http://www.oxygenxml.com
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top