469,270 Members | 1,109 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,270 developers. It's quick & easy.

using document() in a xsl:for-each - newbie

7
hello,
I'm a bit new to XSL and I'm trying to do the following: I have an XML file with a number of profiles in it (profile.xml). I wrote a profile.xsl to transform these files into a nice readable format. Now the user would like to filter these xml files based upon a profile of their choice on the client. I have modified my profile.xsl file to include this filter by hand and it works perfectly. The problem is that I need to read this "filter" from an external file (because it can change) and this is where I have tried to use the document function. Here are some examples of my files:

Profile.xml (shortened):
Expand|Select|Wrap|Line Numbers
  1. <Main>
  2.   <profile id="Profile_1">
  3.     <title>title1</title>
  4.   </profile>
  5.   <profile id="Profile_2">
  6.     <title>title2</title>
  7.   </profile>
  8.   <profile id="Profile_3">
  9.     <title>title3</title>
  10.   </profile>
  11. </Main>
etc...

here is my Profile.xsl (shortened):
Expand|Select|Wrap|Line Numbers
  1. <!--This works....-->
  2. <xsl:for-each select="Main/profile[@id=Profile_1']">
  3. <!--This one does not-->
  4. <!--<xsl:for-each select="document(testing.xml')/ProfileSelection/SelectedProfile)">-->
  5. <td >
  6. <xsl:value-of select="@id"/>
  7. <xsl:value-of select="title"/>
  8. <xsl:apply-templates select="select">
  9. </xsl:apply-templates>
  10. </xsl:for-each>
here is my testing.xml file:
Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <ProfileSelection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml"> 
  3. <SelectedProfile>Benchmark/profile[@id=Profile_1']</SelectedProfile>
  4. </ProfileSelection>
  5.  
This item in my xsl is my problem (I believe):
Expand|Select|Wrap|Line Numbers
  1. <!--<xsl:for-each select="document(testing.xml')/ProfileSelection/SelectedProfile)">-->
the document function does not return a node set in this case, which is what the for-each is looking for. I've tried to use the node-set() function from xmlns:exsl="http://exslt.org/common"> but this has not worked. I am able to verify that the document() is reading the correct string value from the testing.xml file, but for-each just will not use it.

Does anyone know what I am doing wrong?
Thanks in advance,
Pete
Jan 9 '09 #1
15 7043
jkmyoung
2,057 Expert 2GB
You're treating a string
"Benchmark/profile[@id=Profile_1']"
as an xpath to be executed. The processor only recognizes it as a string.

You need to use the exslt function, dyn:execute()
EXSLT - dyn:evaluate
eg: <xsl:for-each select="dyn:evaluate(document(testing.xml')/ProfileSelection/SelectedProfile))">

Unfortunately, this is not implemented on most processors.
Jan 9 '09 #2
Dormilich
8,651 Expert Mod 8TB
you have some syntax violation in your document() call. try this:
Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="document('testing.xml')/ProfileSelection/SelectedProfile">
  2.   <!-- code coming here -->
  3. </xsl:for-each>
and like jkmyoung said, strings won't work for XPath expressions.

regards
Jan 9 '09 #3
vz2d1k
7
Unfortunately I don't have a processor that can handle, natively, the exslt functions and the dyn.xsl file does not seem to exist.
Jan 9 '09 #4
Dormilich
8,651 Expert Mod 8TB
if it's just the profile id that needs customizing, why not storing the value of the id and using that in a comparison.
Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0" encoding="iso-8859-1" ?>
  2. <profile_id>Profile_1</profile_id>
Expand|Select|Wrap|Line Numbers
  1. // ... 
  2. <xsl:variable name="profile" select="document('testing.xml')/profile_id/text()"/>
  3. // ...
  4. <xsl:value-of select="//profile[@id = $profile]"/>
I don't know if there's a better solution, but it should work.
Jan 9 '09 #5
vz2d1k
7
I could do that, only issue is that I have 27 profiles and the xsl code will get very messy.
Jan 9 '09 #6
Dormilich
8,651 Expert Mod 8TB
that depends on what exactly you want to do with that user provided profile name. currently I have no idea what you need them exactly for (ok, I have a dim idea).
Jan 9 '09 #7
vz2d1k
7
Ok, let me try ;-) to explain a little better. When the xml file is created it has all 27 profiles in it. When the user goes to look at these "profile" xml files the xsl puts it into a nice readable format, BUT it shows all the profiles. Some users only want to see, say profile 1 or 2, but they may need at some point to look at another profile. This is why I want them to have all the profiles, but be able to filter on only the profiles they need (so they can print them off and go out into the field with the info).

My idea was to add a combo box to the xsl so they could pick from a drop down what profiles they were interested in. When they did that an onChange event reloaded the page (java script), and wrote out to the testing.xml file what profile they were interested in. then when it reloaded it would show only that profile via the document() function. sounds pretty slick huh? too bad it doesn't work :-(
Jan 9 '09 #8
Dormilich
8,651 Expert Mod 8TB
don't give up yet, I still got some ideas left.
user xml, say 2 profiles to show
Expand|Select|Wrap|Line Numbers
  1. <?xml version="1.0" encoding="iso-8859-1" ?>
  2. <profile>
  3.   <profile_id>Profile_1</profile_id>
  4.   <profile_id>Profile_3</profile_id>
  5. </profiles>
xsl, (rough sketch)
Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="document('user.xml')/profile_id">
  2. <xsl:value-of select="$node[@id = current()/@id]/title"/>
  3. //...
idea: loop over the elements in the user file, that should give you the desired number. the $node variable refers to a <profile> node of the original xml (use <xsl:variable> to define it). current() gets you the node of the for-each loop.

another possibility includes a template using <xsl:with-param> basing on the same principle.
Jan 9 '09 #9
vz2d1k
7
I'll have to play around with that a little bit and try to attack it from that way. thanks Dormilich, I appreciate the help.
Jan 9 '09 #10
Dormilich
8,651 Expert Mod 8TB
nevermind, we're here to help.
Jan 9 '09 #11
jkmyoung
2,057 Expert 2GB
Is it possible for you to generate the XSLT dynamically? Eg when they select a profile, it takes the information from the filter, to create a custom XSLT. Then it runs the base XML through the new XSLT.
Jan 10 '09 #12
vz2d1k
7
jkmyoung, thats what I'm trying to do. As they select a profile from the combo box contained in the xslt, it re-applys the xml to the slightly modified xslt (with a different filter thist time) showing them only their profile.
Jan 12 '09 #13
jkmyoung
2,057 Expert 2GB
What is your encapsulating code for writing the Profile.xsl each time?

Just want to clarify: I mean an entirely new xslt file. No use of document(); no use of of <xsl:param>.
Jan 12 '09 #14
vz2d1k
7
I was using a javascript to write out to the text file. and was only going to do a window.location.reload(); to reload the xsl and the xml, I'm not sure if that will work.
Currently I'm trying Dormilich's idea of using the choose function, but I'm having trouble with that as well. I set a default param at top to be 'all profiles'.
I then draw the combo box with the fixed list of profiles (in xslt code), and an onChange event. So on default the 'all profiles' are loaded. when the user clicks the combo box, on change switches the param to be "profile 1" and fires the reload event. The XSL file has a choose method in it to test the value of my param, i.e. <xsl:when test="*[name() = $selectedProfile] = 'profile1'">. which is not working. I'm not sure how I can test the results from my combo box via the xsl and then reload it accordingly.
Jan 12 '09 #15
jkmyoung
2,057 Expert 2GB
Reread entire thread.
Expand|Select|Wrap|Line Numbers
  1. <xsl:param name="profileId"/>
  2. ....
  3. <xsl:for-each select="Main/profile[@id=$profileId]"> 
  4.  
What javascript xslt processor are you using? (eg. post code). Might be something like:
Expand|Select|Wrap|Line Numbers
  1. xslproc = xslt.createProcessor();
  2. xslproc.input = xmldoc;
  3. xslproc.addParameter("profileId", comboBoxValue);
  4.  
Depends on the XSLT processor you're using.
Jan 13 '09 #16

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

13 posts views Thread by Stumped and Confused | last post: by
5 posts views Thread by Randall | last post: by
1 post views Thread by =?Utf-8?B?RGF2aWRHQg==?= | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by suresh191 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.