Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Rachael Parker 12 posts 32 karma points
    Oct 14, 2011 @ 11:33
    Rachael Parker
    0

    How do I make a dynamic xslt query

    Hi,

     

    I am building my first site in Umbraco and will admit that I am rubbish at Xslt.

    I have a simple search form with 3 drop down options (propertytype, area, bedrooms).

    I want my xslt to check if an option is empty and if it isn't then add the field to my query string. 

    I found this post http://www.blogfodder.co.uk/2009/12/22/building-a-dynamic-xpath-statement-in-xslt but I couldn't get this to work.

    Any pointers would be greatfully received as it is starting to drive me a bit mad

  • Dirk De Grave 4541 posts 6021 karma points MVP 3x admin c-trib
    Oct 14, 2011 @ 11:52
    Dirk De Grave
    0

    Hi Rachael,

    Could you show us some code, cause i'm not exactly sure what you're trying to do here. Have some examples or result you're aiming for?

     

    Cheers,

    /Dirk

  • Rodion Novoselov 694 posts 859 karma points
    Oct 14, 2011 @ 12:02
    Rodion Novoselov
    0

    Hi. It seems to me that in fact the issue has little to do with XSLT itself and all you need actually is to put your drop-down list inside the form with method="GET". And then set proper values to the option elements in the xslt that renders the <select> tag. Since the form has method="GET" a selected value will be sent to the server inside the query string.

  • Rachael Parker 12 posts 32 karma points
    Oct 14, 2011 @ 12:27
    Rachael Parker
    0

    I have the form using GET and sending the variables to the results page and if I just want to do exact matches I can get it to work. But I need it to work if someone sends through just one of the values. so If they only send through the area it won't try to use the property type and bedrooms in the search as this won't return any values.

     

    This is what I got using that blog post. However when I try to save it I  get errors

    System.Xml.XmlException: Name cannot begin with the ' ' character, hexadecimal value 0x20. Line 29, position 67. 

    and/or

    System.Xml.Xsl.XslTransformException: Extension functions cannot return null values. 

     apologies for my Xslt but this is the first time i've ever had to use it!

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet 
      version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:msxml="urn:schemas-microsoft-com:xslt"
    xmlns:ps="urn:anynamehere:xslt"
      xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:umbraco.contour="urn:umbraco.contour" 
      exclude-result-prefixes="ps msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets umbraco.contour ">


    <xsl:output method="xml" omit-xml-declaration="yes"/>

    <xsl:param name="currentPage"/>

    <xsl:template match="/">

    <!-- start writing XSLT -->
      
      <xsl:variable name="type" select="umbraco.library:RequestQueryString('type')"/>
      <xsl:variable name="area" select="umbraco.library:RequestQueryString('area')" />
      <xsl:variable name="beds" select="umbraco.library:RequestQueryString('bedrooms')" />
     
     <!-- ############  Build up the xpath portions
    (note: any variables or umbraco.library functions or other extensions must be inserted with xsl:value-of)
    ############## -->
    <xsl:variable name="distanceXpath" >
    string-length($type) &gt; 0
    and $type <xsl:value-of select="propertyType" />
    <!-- just keep adding more conditions here to build up your xpath -->
    </xsl:variable>
    <!-- ############  End xpath portions ############## -->
      
      <!-- once you've got the xpath string, use ps:evaluateXpath and check that it returns
    'True' to actually process the xpath statement -->
    <xsl:variable name="searchResults" select="$currentPage/ancestor-or-self::root//Property [ps:evaluateXpath(., $distanceXpath) = 'True']"/>
      
     <!-- <xsl:for-each select="$currentPage/ancestor-or-self::root//Property [@isDoc and leased != 1]">-->
      <xsl:for-each select="$searchResults" >
        <xsl:value-of select="@nodeName" />
         <br />
          <xsl:value-of select="propertyType" />
         <br />
          <xsl:value-of select="bedrooms" />
         <br />
          <xsl:value-of select="area" />
        <br /> <br />
        
      </xsl:for-each>
      

    </xsl:template>
    <msxml:script language="C#" implements-prefix="ps" >
    <![CDATA[
    public string evaluateXpath(XPathNodeIterator nodes, string xpath){
    /* this is intended for a SINGLE node to be passed in, although the type is XPathNodeIterator; if multiple
    nodes are passed in, only the first one will be evaluated */
    try{
    while (nodes.MoveNext()){
    XPathNavigator n = nodes.Current as XPathNavigator;
    return n.Evaluate(xpath).ToString();
    }
    }catch{
    return null;
    }
    return null;
    }
    ]]>
    </msxml:script>
    </xsl:stylesheet>

     

     

     

     

     

     

  • Rodion Novoselov 694 posts 859 karma points
    Oct 14, 2011 @ 12:49
    Rodion Novoselov
    1

    Oh, well, probably i got what you want. If you need something like building an xpath query on-the-fly, usually a trick like this is helpfull:

    <xsl:variable name="whatToSearch" select="...."/>
    <xsl:variable name="whereToSearch" select="...."/>
    ...
    <!- xpath is below: -->
    <xsl:bla-bla-bla select="./*[local-name() = $whereToSearch and . = $whatToSearch]" />
    <!-- or: -->
    <xsl:bla-bla-bla select="./@*[local-name() = $whereToSearch and . = $whatToSearch]" /> 

    The idea here is that you select all elements (*) or attriburtes (@*), but filter them by a local-name() = '...' condition

  • Rachael Parker 12 posts 32 karma points
    Oct 14, 2011 @ 15:17
    Rachael Parker
    0

    Sorry I really don't understand what I would do with that!

  • Rodion Novoselov 694 posts 859 karma points
    Oct 14, 2011 @ 15:43
    Rodion Novoselov
    0

    Rachael, am I right that you want to achieve this (the usual xslt header is omited):

    <xsl:variable name="type" select="umbraco.library:RequestQueryString('type')"/> 
    <xsl:variable name="value">
    <xsl:if test="$type = 'area'">
    <xsl:value-of select="
    umbraco.library:RequestQueryString('area')"/>
    </xsl:if>
    <xsl:if test="$type = 'beds'">
    <xsl:value-of select="umbraco.library:RequestQueryString('bedrooms')"/> </xsl:if>
    </xsl:variable>

    <xsl:template match="/">
    <xsl:for-each select="$currentPage//*[@isDoc and *[local-name() = $type and . = $value]]">
    <xsl:if test="position() > 1">
    <br/><br/>
    </xsl:if>
    <xsl:value-of select="@nodeName"/>
    <br/>
    <xsl:value-of select="$type"/>
    <br/>
    <xsl:value-of select="$value"/>
    </xsl:for-each>
    </xsl:template>

    The main select in xsl:for-each means: "Select all descendant documents that have a property named $type with the value of $value". By the previous assignments the $type will be the 'type' from the query string and the $value will be either 'area' or 'beds' therefrom depending on the value of 'type'.

  • Rachael Parker 12 posts 32 karma points
    Oct 14, 2011 @ 16:26
    Rachael Parker
    0

    sort of,

    I get 3 values passed through to my results page, type, area and bedrooms. So I need to build the query string so it searches for type=propertyType AND area=propertyArea AND bedrooms = propertyBedrooms but only adding each condition if the passed through value != null

     

    sorry for being a pain! 

  • Rodion Novoselov 694 posts 859 karma points
    Oct 14, 2011 @ 19:10
    Rodion Novoselov
    0

    Ok, that's much clearer now. And it's turned out to be simpler than it seemed initially.  So, change it this way:

    <xsl:variable name="type" select="umbraco.library:RequestQueryString('type')"/> 
    <xsl:variable name="area" select="umbraco.library:RequestQueryString('area')"/>
    <xsl:variable name="beds" select="umbraco.library:RequestQueryString('bedrooms')"/>
    
    <xsl:template match="/">
      <xsl:for-each select="$currentPage//*[@isDoc and ($type = '' or type = $type) and ($area = '' or area = $area) and ($beds = '' or beds = $beds)]">
        <xsl:if test="position() > 1">
          <br/><br/>
        </xsl:if>
        <xsl:value-of select="@nodeName"/>
        <br/>
        <xsl:value-of select="$type"/>
        <br/>
        <xsl:value-of select="$value"/>
      </xsl:for-each>
    </xsl:template>

    Does it fit?

  • Rachael Parker 12 posts 32 karma points
    Oct 17, 2011 @ 10:31
    Rachael Parker
    0

    Hi, thank you that works perfectly

    you have saved me from my third xslt induced nervous breakdown :)

Please Sign in or register to post replies

Write your reply to:

Draft