1.) What if I only want to show faculty members that work in Building 1 on a certain page? ( dataType=facultyBuilding ) How do I modify the SELECT statement?
2.) And can I do this without creating a brand new XSLT file? To explain what I mean: I might have several pages.. building 1, building 2, building 3, ect.. each one I would like to list the faculty members that work inside that building. I would prefer not to have X number of versions of "basically" the same .XSLT file. This would become a little bit of a headache as I update the code because I would be forced to update it X number of times.
.. to in order to make this xslt file work no matter where the "building 1" or "building 2" page was located in my file tree? Most likley just use the ID right? (see below)
**Note the dataType=facultyBuilding is a group of check boxes and an admin can select multiple locations for one faculty member.. just in case that would make any difference
Thanks for getting back to me. I only have 2 sample profiles created so far.. but here is the XML
<FacultyDatabase id="6394" parentID="1100" level="2" writerID="0" creatorID="0" nodeType="6390" template="6398" sortOrder="0" createDate="2013-04-04T08:37:06" updateDate="2013-04-11T09:59:31" nodeName="Faculty Database" urlName="faculty-database" writerName="administrator" creatorName="administrator" path="-1,1100,6394" isDoc=""> <FacultySearch id="6412" parentID="6394" level="3" writerID="0" creatorID="0" nodeType="6411" template="6410" sortOrder="0" createDate="2013-04-06T13:06:35" updateDate="2013-04-11T09:59:31" nodeName="Search" urlName="search" writerName="administrator" creatorName="administrator" path="-1,1100,6394,6412" isDoc="" /> <FacultyProfile id="6395" parentID="6394" level="3" writerID="0" creatorID="0" nodeType="6392" template="6397" sortOrder="1" createDate="2013-04-04T08:41:04" updateDate="2013-05-17T12:01:31" nodeName="David Thompson" urlName="david-Thompson" writerName="administrator" creatorName="administrator" path="-1,1100,6394,6395" isDoc=""> <facultyWebsite>http://www.cohpa.ucf.edu</facultyWebsite>; <facultyFacebook>http://facebook.com</facultyFacebook>; <facultyLinkedin>http://linkedin.com</facultyLinkedin>; <facultyTwitter>http://twitter.com</facultyTwitter>; <facultyGooglePlus>http://google.com</facultyGooglePlus>; <facultyYouTube>http://youtube.com</facultyYouTube>; <facultyResearch><![CDATA[ <p>There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All the Lorem Ipsum generators on the Internet tend to repeat predefined chunks as necessary, making this the first true generator on the Internet. It uses a dictionary of over 200 Latin words, combined with a handful of model sentence structures, to generate Lorem Ipsum which looks reasonable. The generated Lorem Ipsum is therefore always free from repetition, injected humour, or non-characteristic words etc.</p> ]]></facultyResearch> <facultyResearchInterests><![CDATA[Design,css,wordpress,Websites,Marketing,PHP,.NET]]></facultyResearchInterests> <facultyCV>/media/306394/instructions.pdf</facultyCV> <facultyBio><![CDATA[ <p><span class="xml-punctuation"><strong>Lorem Ipsum</strong> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release <a href="/{localLink:1100}" title="Home">of Letraset sheets containing</a> Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</span></p> ]]></facultyBio> <facultyFirstName>David</facultyFirstName> <facultyImage>/media/308505/instagram-logo.jpg</facultyImage> <facultyPub /> <title>David Thompson | UCF Faculty &amp; Staff | College of Health &amp; Public Affairs</title> <description><![CDATA[David Thompson is a faculty and staff employee at the College of Health & Public Affairs at the University of Central Florida. UCF]]></description> <keywords><![CDATA[David Thompson, faculty, staff, professor, cohpa, ucf, central florida, university of central florida, college of health and public affairs]]></keywords> <facultyAddLinks> <multi-url-picker> <url-picker mode="URL"> <new-window>False</new-window> <node-id /> <url>http://www.skyhive.com</url>; <link-title>SKYHIVE</link-title> </url-picker> <url-picker mode="URL"> <new-window>False</new-window> <node-id /> <url>http://mysite.com</url>; <link-title>mysite</link-title> </url-picker> <url-picker mode="URL"> <new-window>False</new-window> <node-id /> <url>test</url> <link-title>test</link-title> </url-picker> <url-picker mode="URL"> <new-window>False</new-window> <node-id /> <url>test</url> <link-title>test</link-title> </url-picker> </multi-url-picker> </facultyAddLinks> <facultyCrop> <crops date="2013-04-05T19:42:10"> <crop name="ucf_faculty" x="31" y="36" x2="466" y2="535" url="/media/308505/instagram-logo_ucf_faculty.jpg" /> </crops> </facultyCrop> <facultyLastName>Thompson</facultyLastName> <facultyDegrees /> <facultyLightbox>0</facultyLightbox> <facultyJobTitle><![CDATA[Web Developer]]></facultyJobTitle> <facultyPhone>407-823-5884</facultyPhone> <facultyEmail>[email protected]</facultyEmail> <facultyBuilding><![CDATA[HPA I]]></facultyBuilding> <facultyRoom>341</facultyRoom> <facultyDepartment><![CDATA[Criminal Justice]]></facultyDepartment> <facultyDate /> <facultyAffiliations><![CDATA[Diversity Committee,Umbraco Developer,Photoshop Experts]]></facultyAffiliations> </FacultyProfile> <FacultyProfile id="6399" parentID="6394" level="3" writerID="0" creatorID="0" nodeType="6392" template="6397" sortOrder="2" createDate="2013-04-04T12:55:39" updateDate="2013-04-17T10:39:43" nodeName="Karen Guin" urlName="karen-guin" writerName="administrator" creatorName="administrator" path="-1,1100,6394,6399" isDoc=""> <facultyWebsite /> <facultyFacebook /> <facultyLinkedin /> <facultyTwitter /> <facultyGooglePlus /> <facultyYouTube /> <facultyResearch><![CDATA[]]></facultyResearch> <facultyResearchInterests><![CDATA[application,communication]]></facultyResearchInterests> <facultyCV /> <facultyBio><![CDATA[]]></facultyBio> <facultyFirstName>Karen</facultyFirstName> <facultyImage /> <facultyPub /> <title>Karen Guin | UCF Faculty &amp; Staff | College of Health &amp; Public Affairs</title> <description><![CDATA[Karen Guin is a faculty and staff employee at the College of Health & Public Affairs at the University of Central Florida. UCF]]></description> <keywords><![CDATA[Karen Guin, faculty, staff, professor, cohpa, ucf, central florida, university of central florida, college of health and public affairs]]></keywords> <facultyAddLinks> <multi-url-picker /> </facultyAddLinks> <facultyCrop><![CDATA[]]></facultyCrop> <facultyLastName>Guin</facultyLastName> <facultyDegrees /> <facultyLightbox>0</facultyLightbox> <facultyJobTitle><![CDATA[Director of Communications]]></facultyJobTitle> <facultyPhone /> <facultyEmail /> <facultyBuilding><![CDATA[]]></facultyBuilding> <facultyRoom /> <facultyDepartment><![CDATA[Dean's Office]]></facultyDepartment> <facultyDate /> <facultyAffiliations><![CDATA[]]></facultyAffiliations> </FacultyProfile> </FacultyDatabase>
If so, you could possibly use a query string to help out:
<xsl:variable name="building" select="umbraco.library:RequestQueryString('b')" /> <xsl:for-eachselect="umbraco.library:GetXmlNodeById(6394)/FacultyProfile/facultyBuilding='$building'/.."><!-- the double dots go back up one level--> <xsl:value-of select="./title"/> </xsl:for-each>
I think what I am looking for is a way to modify my selection based on the page that I am currently on... something that allows me to have logic like this:
ONLY SHOW FACULTY THAT WORK IN HPA I If current pageID=20 then <xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc] ONLY WHERE facultyBuilding=HPA I">
ONLY SHOW FACULTY THAT WORK IN HPA II If current pageID=30 then <xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc] ONLY WHERE facultyBuilding=HPA II">
(ELSE) SHOW EVERYONE... <xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc]">
Something like that would allow me to drop the same XSLT macro into multiple pages, and yet be able to control what results are rendered. Not to mention allow me to only have one XSLT file for all of the pages that I will ultimately use it on.
Does that help?
**Note when I write "ONLY WHERE facultyBuilding=HPA I" ... i know thats not correct formmatting.. I'm not sure how to write that logic yet.
OK, thought I should explain a little further and provide a sample of how to do the fallback. Here goes:
<!-- Grab a reference to the FacultyDatabase node -->
<xsl:variable name="facultyDB" select="umbraco.library:GetXmlNodeById(6394)" />
<!-- Grab the facultyBuilding property on the current page (if any) -->
<xsl:variable name="selectedFaculty" select="$currentPage/facultyBuilding" />
<!-- Select all profiles -->
<xsl:variable name="profiles" select="$facultyDB/FacultyProfile" />
<!--
This next one does the equivalent of this SQL:
SELECT * FROM profiles WHERE facultyBuilding = $selectedFaculty
-->
<xsl:variable name="filtered" select="$profiles[facultyBuilding = $selectedFaculty]" />
<!-- Process either the filtered profiles or all profiles (*) -->
<xsl:apply-templates select="$filtered | $profiles[not($filtered)]" />
<!-- Template for a profile -->
<xsl:template match="FacultyProfile">
<p>
<!-- Output for profile -->
<xsl:value-of select="@nodeName" />
</p>
</xsl:template>
(*): Works like this:
In XPath the pipe (|) is used to combine node sets - here we do some trickery;
$filtered is the set of filtered nodes (could be empty)
$profiles id the complete set of profiles - by adding the predicate [not($filtered)] to this, we essentially only put the $profiles set in if the filtered set is empty (because an empty set will return a boolean false - by flipping that with the not() function, we end up with EITHER the filtered set OR the complete set).
The hardest part of this is usually getting the hang of "sets" - but they're essential in learning to do what XSLT was built for.
Ok so I've been working on a few ways to do this.. but I think I will need something that allows me to specify the results per page since the dataTypes won't be present on the current page showing the filtered results.
This of course doesn't work, and I'm not sure how to get there... but this would allow me to really control the results on any page that I want to. I could filter the profiles by all kinds of dataTypes besides just facultyBuilding.
I'm still trying to generate this code in order to filter results:
What I would like to be able to do is drop this one Macro into the WYSIWYG editor of several basic pages created in various un-related sections of my site. Those pages wont have defined variables that relate to the desired building that I want to display.
For example http://mysite.com/socialwork/faculty/ ; <-- on this page I'll drop in the 1 macro and only list faculty from my full list that work in the Social Work Department. Same thing goes for http://mysite.com/criminaljustice/faculty/ ; <-- that exact same macro can be placed and yet only display the Criminal Justice Faculty
If I use the method you provided in your last comment, this would allow me to manage one XSLT file and I could easily retreive any specific list segment on any specific page.
I'm still pretty young with my knowledge of Umbraco, I'm actually still working on my first project so forgive me if a query string would solve it, I might just not be seeing the picture clearly as I have not used those before.
Thanks anyway for your help, I really appreciate it.
Error occured System.Xml.Xsl.XslLoadException: Expression must evaluate to a node-set.
...NodeById(6394)//facultyBuilding= -->'$facultyFilter'<-- /.. An
error occurred at
D:\Inetpub\wwwroot\Umbraco\xslt\635047304797900861_temp.xslt(43,1).
at System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
at umbraco.presentation.webservices.codeEditorSave.SaveXslt(String
fileName, String oldName, String fileContents, Boolean ignoreDebugging)
needs to be able to display ALL faculty.. right now it displays the faculty members that have NO building listed.
So this is a little too specific because I may also want to retreive a list like facultyDepartment=Social Work or facultyResearch=Health Care stuff like that.
The wall you're hitting is that you can't dynamically create an XPath expression to use - there is an extension GetXmlNodesByXPath() which you may be able to use, but it has its own quirks regarding context...
You can try using this approach, though - using an XML variable to configure the nodes you need to lookup:
<!-- Build an XML variable with all the filters available -->
<xsl:variable name="filterProxy">
<filter id="6624" property="facultyBuilding" value="HPA I" />
<filter id="3385" property="facultyDepartment" value="Social Work" />
<!-- ETC. -->
</xsl:variable>
<!-- Grab the filter that applies to this page -->
<xsl:variable name="facultyFilter" select="msxml:node-set($filterProxy)/filter[@id = $currentPage/@id]" />
<!-- Grab the root node to do lookups under -->
<xsl:variable name="rootNode" select="umbraco.library:GetXmlNodeById(6394)" />
<!-- Use the filter -->
<xsl:for-each select="$rootNode/FacultyProfile[*[name() = $facultyFilter/@property] = $facultyFilter/@value]">
<p>
<xsl:value-of select="@nodeName" />
<!-- ETC. -->
</p>
</xsl:for-each>
(The msxml:node-set() function is needed to enable XPath querying on an XML variable)
I don't remember if you need a default ("all") filter - but we'll tackle that afterwards then...
Well I certainly appreciate learning that it was an imposibility with the direction I was going.. thank you.
I gave your method a shot as soon as I got in this morning but was hit with an error right away:
Error occured System.Xml.Xsl.XslLoadException:
Prefix 'umbraco' is not defined. An error occurred at
D:\Inetpub\wwwroot\Umbraco\xslt\635048052026124261_temp.xslt(38,1).
at System.Xml.Xsl.XslCompiledTransform.LoadInternal(Object stylesheet, XsltSettings settings, XmlResolver stylesheetResolver)
at umbraco.presentation.webservices.codeEditorSave.SaveXslt(String
fileName, String oldName, String fileContents, Boolean ignoreDebugging)
Thank you again for your time already with this.. I can't wait to have this resolved.
Thanks again for all the help so far. I haven't been able to figure out how to display a default ("all") path. Any final help that you or anyone else could provide would be amazing.
The pipe is used to join nodesets - here we're adding a nodeset that's built from all the FacultyProfile nodes - but only if the $facultyFilter didn't match any of the predefined ones...
<!-- Build an XML variable with all the filters available -->
<xsl:variable name="filterProxy">
<filter id="6624" property="facultyBuilding" value="HPA I" />
<filter id="3385" property="facultyDepartment" value="Social Work" />
<!-- ETC. -->
</xsl:variable>
<!-- Grab the filter that applies to the current page -->
<xsl:variable name="facultyFilter" select="msxml:node-set($filterProxy)/filter[@id = $currentPage/@id]" />
<!-- Grab the root node to do lookups under -->
<xsl:variable name="rootNode" select="umbraco.library:GetXmlNodeById(6394)" />
<!-- Filter the FacultyProfile nodes using the filter (or return all of them if no filter matched) -->
<xsl:for-each
select="$rootNode/FacultyProfile[*[name() = $facultyFilter/@property] = $facultyFilter/@value]
| $rootNode/FacultyProfile[not($facultyFilter)]">
<p>
<xsl:value-of select="@nodeName" />
<!-- ETC. -->
</p>
</xsl:for-each>
Dynamically Retrieve Items by Datatype Value
*Using Umbraco v4.8
This code currently calls all the Faculty Profiles (nodes) that I create and sorts them by the dataType=facultyLastName
1.) What if I only want to show faculty members that work in Building 1 on a certain page? ( dataType=facultyBuilding )
How do I modify the SELECT statement?
2.) And can I do this without creating a brand new XSLT file?
To explain what I mean: I might have several pages.. building 1, building 2, building 3, ect.. each one I would like to list the faculty members that work inside that building. I would prefer not to have X number of versions of "basically" the same .XSLT file. This would become a little bit of a headache as I update the code because I would be forced to update it X number of times.
3.) What could I change...
.. to in order to make this xslt file work no matter where the "building 1" or "building 2" page was located in my file tree? Most likley just use the ID right? (see below)
**Note the dataType=facultyBuilding is a group of check boxes and an admin can select multiple locations for one faculty member.. just in case that would make any difference
Comment author was deleted
Please provide the XML from the umbraco.config file for node 6394.
Is the datatype your are referencing on the document?
Hello Kevin,
Thanks for getting back to me. I only have 2 sample profiles created so far.. but here is the XML
Comment author was deleted
Is this line the data that is being saved for the building?
If so, you could possibly use a query string to help out:
Note: untested code
Then you pass which building by query...
http://mydomain/mypage.aspx?b=hpa%20i
and so on.
I hope I understood the question enough to help
I think what I am looking for is a way to modify my selection based on the page that I am currently on... something that allows me to have logic like this:
If current pageID=20 then <xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc] ONLY WHERE facultyBuilding=HPA I">
If current pageID=30 then <xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc] ONLY WHERE facultyBuilding=HPA II">
<xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc]">
Something like that would allow me to drop the same XSLT macro into multiple pages, and yet be able to control what results are rendered. Not to mention allow me to only have one XSLT file for all of the pages that I will ultimately use it on.
Does that help?
**Note when I write "ONLY WHERE facultyBuilding=HPA I" ... i know thats not correct formmatting.. I'm not sure how to write that logic yet.
Hi FarmFreshCode,
Have you got a facultyBuilding property on those pages (e.g. pageID=20 has the same checkboxes and the ones selected are the ones to lookup)?
That would allow you to check for those and to fallback to showing everything if no boxes are checked on the "lookup" page.
As for "ONLY WHERE" - if you add another predicate (an expresseion in square brackets) that will work as such, e.g.:
/Chriztian
OK, thought I should explain a little further and provide a sample of how to do the fallback. Here goes:
(*): Works like this:
In XPath the pipe (|) is used to combine node sets - here we do some trickery;
The hardest part of this is usually getting the hang of "sets" - but they're essential in learning to do what XSLT was built for.
Hello Chriztian,
Thanks so much for your help! As far as your first post...
How easy is that?!?!! very nice. Looking forward to using that.
As for your second, I'll hopefully get to test this out soon, but it looks very promising. Thank you again for your time and help.
Ok so I've been working on a few ways to do this.. but I think I will need something that allows me to specify the results per page since the dataTypes won't be present on the current page showing the filtered results.
This of course doesn't work, and I'm not sure how to get there... but this would allow me to really control the results on any page that I want to. I could filter the profiles by all kinds of dataTypes besides just facultyBuilding.
I'm still trying to generate this code in order to filter results:
But I haven't been able to figure out how to add a variable there in order to add it dynamically. Any futher help would be great.
Thanks!
Comment author was deleted
Why can't you use the query string idea? Are you trying to avoid having a query string?
Otherwise you are making static mappings which IMHO defeats the purpose.
Your code will work like this though:
Hi Kevin, thanks so much for the follow up.
What I would like to be able to do is drop this one Macro into the WYSIWYG editor of several basic pages created in various un-related sections of my site. Those pages wont have defined variables that relate to the desired building that I want to display.
For example http://mysite.com/socialwork/faculty/ ; <-- on this page I'll drop in the 1 macro and only list faculty from my full list that work in the Social Work Department.
Same thing goes for http://mysite.com/criminaljustice/faculty/ ; <-- that exact same macro can be placed and yet only display the Criminal Justice Faculty
If I use the method you provided in your last comment, this would allow me to manage one XSLT file and I could easily retreive any specific list segment on any specific page.
I'm still pretty young with my knowledge of Umbraco, I'm actually still working on my first project so forgive me if a query string would solve it, I might just not be seeing the picture clearly as I have not used those before.
Thanks anyway for your help, I really appreciate it.
Hi Kevin,
So when I place your code in:
I get the following error:
Comment author was deleted
My fault, try:
Comment author was deleted
or this if that don't work:
Comment author was deleted
Crap, lose the single quotes:
Ok the last one you sent seems to work for me.. however the OTHERWISE statement in
needs to be able to display ALL faculty.. right now it displays the faculty members that have NO building listed.
So this is a little too specific because I may also want to retreive a list like facultyDepartment=Social Work or facultyResearch=Health Care stuff like that.
Getting really close though
There is also a SEARCH node as a child of my Faculty Database
umbraco.library:GetXmlNodeById(6394)
So I still want to make sure I'm only pulling the FacultyProfile docType nodes in my results.
I wish this would work for me:
my it just seems to retrieve all faculty members with no apparent filter on the results..
even though:
<xsl:for-each select="umbraco.library:GetXmlNodeById(6394)/FacultyProfile [@isDoc][facultyBuilding = 'HPA I']">
works perfectly..
Comment author was deleted
Try this:
Hi Kevin,
Yeah I tried something similar to that, however because I need the For-Each statement to remain open it throws errors.
If I open and close the for-each statement like you have posted
then is wont include all the data points that need to be pulled per node that come later in the XSLT file.
Not to mention that:
unfortunately this format doesn't seem to work for me. All I get is the full unfiltered listing of all faculty members.
Here's another format that I've tried, but without luck..
as well as this one...
They still just show ALL faculty... not just the ones in building HPA I
Hi again,
The wall you're hitting is that you can't dynamically create an XPath expression to use - there is an extension GetXmlNodesByXPath() which you may be able to use, but it has its own quirks regarding context...
You can try using this approach, though - using an XML variable to configure the nodes you need to lookup:
(The msxml:node-set() function is needed to enable XPath querying on an XML variable)
I don't remember if you need a default ("all") filter - but we'll tackle that afterwards then...
/Chriztian
Well I certainly appreciate learning that it was an imposibility with the direction I was going.. thank you.
I gave your method a shot as soon as I got in this morning but was hit with an error right away:
Thank you again for your time already with this.. I can't wait to have this resolved.
Ah - silly me - umbraco:library:GetXmlNodeById(6394)
should be
umbraco.library:GetXmlNodeById(6394)
(That's a dot (.) instead of a colon (:) between "umbraco" and "library")
/Chriztian
(UPDATE: Edited the above code sample to fix the typo)
Ah.. I didnt catch that.. works perfectly! THANKS Chriztian Steinmeier!!
I still need to get a DISPLAY ALL option.. but this is a great step! THANKS!
Hello Chriztian,
Thanks again for all the help so far. I haven't been able to figure out how to display a default ("all") path. Any final help that you or anyone else could provide would be amazing.
Thanks.
Hi FarmFreshCode,
I'm almost sure you should be able to do this:
The pipe is used to join nodesets - here we're adding a nodeset that's built from all the FacultyProfile nodes - but only if the $facultyFilter didn't match any of the predefined ones...
Give it a spin and let me know how it fares.
/Chriztian
NICE! Nailed it!!!
Would you mind putting the full script together in a post so that I could mark it as "Solved" by you?
Thank you so much! I really need to create a Thank you page on this site and link to all of the great helpers like yourself.
Great :-)
Here's the final bits combined:
/Chriztian
is working on a reply...