Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. XML / XSL
  4. XSLT passing a variable to starts-with

XSLT passing a variable to starts-with

Scheduled Pinned Locked Moved XML / XSL
xmljavascript
8 Posts 3 Posters 29 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    B Offline
    bjmallon
    wrote on last edited by
    #1

    I've got an XML file full of user details including 'FirstName', 'Surname' and 'StreetAddress'. Currently my XSL file has a template (SurnameAlphabetGrouping) that groups users by the first character of the Surname element's value. I've only provided the process for 'A' to save space. All 26 letters are processed.

          [+ A ()](javascript:void\(0\))
    

    That's all well and good. But now that I've got it working that way, I really want to make it smarter (i.e. cut down the code), so I'm trying to build a template that can take the required character as a parameter. I've got a variable (Letters) that carries tokens for the 26 letters of the alphabet:

    I'm then attempting to process each token, passing it to the template as a parameter:

    This is the template as it stands at the moment:

    L Richard DeemingR 2 Replies Last reply
    0
    • B bjmallon

      I've got an XML file full of user details including 'FirstName', 'Surname' and 'StreetAddress'. Currently my XSL file has a template (SurnameAlphabetGrouping) that groups users by the first character of the Surname element's value. I've only provided the process for 'A' to save space. All 26 letters are processed.

            [+ A ()](javascript:void\(0\))
      

      That's all well and good. But now that I've got it working that way, I really want to make it smarter (i.e. cut down the code), so I'm trying to build a template that can take the required character as a parameter. I've got a variable (Letters) that carries tokens for the 26 letters of the alphabet:

      I'm then attempting to process each token, passing it to the template as a parameter:

      This is the template as it stands at the moment:

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      Start with a smaller "select"; one that actually finds something. Then start picking up more chars until it breaks. Then you will know why.

      "(I) am amazed to see myself here rather than there ... now rather than then". ― Blaise Pascal

      1 Reply Last reply
      0
      • B bjmallon

        I've got an XML file full of user details including 'FirstName', 'Surname' and 'StreetAddress'. Currently my XSL file has a template (SurnameAlphabetGrouping) that groups users by the first character of the Surname element's value. I've only provided the process for 'A' to save space. All 26 letters are processed.

              [+ A ()](javascript:void\(0\))
        

        That's all well and good. But now that I've got it working that way, I really want to make it smarter (i.e. cut down the code), so I'm trying to build a template that can take the required character as a parameter. I've got a variable (Letters) that carries tokens for the 26 letters of the alphabet:

        I'm then attempting to process each token, passing it to the template as a parameter:

        This is the template as it stands at the moment:

        Richard DeemingR Offline
        Richard DeemingR Offline
        Richard Deeming
        wrote on last edited by
        #3

        Are you absolutely certain that the character parameter is getting the correct string value? I've just tried the following simplified example, and it works as expected:

        <?xml version="1.0"?>
        <bookstore>
        <book>
        <title>The Weather Pattern</title>
        <author>Weather Man</author>
        <price>100.00</price>
        </book>
        <book>
        <title>Weaving Patterns</title>
        <author>Weaver</author>
        <price>150.00</price>
        </book>
        <book>
        <title>Speech Pattern</title>
        <author>Speaker</author>
        <price>15.00</price>
        </book>
        <book>
        <title>Writing Style</title>
        <author>Writer</author>
        <price>1500.00</price>
        </book>
        </bookstore>

        <?xml version="1.0"?>
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:template match="/">
        <root>
        <xsl:apply-templates select="/bookstore">
        <xsl:with-param name="character" select="'W'" />
        </xsl:apply-templates>
        </root>
        </xsl:template>

        <xsl:template match="bookstore">
            <xsl:param name="character" select="''" />
            <xsl:variable name="charMatch" select="book\[starts-with(title, $character)\]"/>    
            <xsl:variable name="charCount" select="count($charMatch)"/>
            
            <result>
                <char><xsl:value-of select="$character" /></char>
                <count><xsl:value-of select="$charCount" /></count>
                <books>
                    <xsl:for-each select="$charMatch">
                        <xsl:copy-of select="." />
                    </xsl:for-each>
                </books>
            </result>
        </xsl:template>
        

        </xsl:stylesheet>


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

        B 1 Reply Last reply
        0
        • Richard DeemingR Richard Deeming

          Are you absolutely certain that the character parameter is getting the correct string value? I've just tried the following simplified example, and it works as expected:

          <?xml version="1.0"?>
          <bookstore>
          <book>
          <title>The Weather Pattern</title>
          <author>Weather Man</author>
          <price>100.00</price>
          </book>
          <book>
          <title>Weaving Patterns</title>
          <author>Weaver</author>
          <price>150.00</price>
          </book>
          <book>
          <title>Speech Pattern</title>
          <author>Speaker</author>
          <price>15.00</price>
          </book>
          <book>
          <title>Writing Style</title>
          <author>Writer</author>
          <price>1500.00</price>
          </book>
          </bookstore>

          <?xml version="1.0"?>
          <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:template match="/">
          <root>
          <xsl:apply-templates select="/bookstore">
          <xsl:with-param name="character" select="'W'" />
          </xsl:apply-templates>
          </root>
          </xsl:template>

          <xsl:template match="bookstore">
              <xsl:param name="character" select="''" />
              <xsl:variable name="charMatch" select="book\[starts-with(title, $character)\]"/>    
              <xsl:variable name="charCount" select="count($charMatch)"/>
              
              <result>
                  <char><xsl:value-of select="$character" /></char>
                  <count><xsl:value-of select="$charCount" /></count>
                  <books>
                      <xsl:for-each select="$charMatch">
                          <xsl:copy-of select="." />
                      </xsl:for-each>
                  </books>
              </result>
          </xsl:template>
          

          </xsl:stylesheet>


          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

          B Offline
          B Offline
          bjmallon
          wrote on last edited by
          #4

          Richard, Thanks for your reply. Yes, if I pass 'A' to the template, I get the correct answer. So that's a good thing. Now, given a tokenised string stored in a variable (Letters):

          And trying to process each token through the template:

          What should I be using inside the 'select' attribute to ensure that i get 'A' and not some other value. Some options I've tried, debugging in Visual Studio 2013, are:

          This gives me:

          $currToken {Dimension:[1]}
          [1] /
          node()[1] A

          'select="./node()"' gives me the same answer. 'select="./node()[1]"' gives me the same answer. I haven't had any help from Google, as I can't seem to ask the right question, or nobody's doing this. What do I need to put into the select to actually get the character A.

          Richard DeemingR 1 Reply Last reply
          0
          • B bjmallon

            Richard, Thanks for your reply. Yes, if I pass 'A' to the template, I get the correct answer. So that's a good thing. Now, given a tokenised string stored in a variable (Letters):

            And trying to process each token through the template:

            What should I be using inside the 'select' attribute to ensure that i get 'A' and not some other value. Some options I've tried, debugging in Visual Studio 2013, are:

            This gives me:

            $currToken {Dimension:[1]}
            [1] /
            node()[1] A

            'select="./node()"' gives me the same answer. 'select="./node()[1]"' gives me the same answer. I haven't had any help from Google, as I can't seem to ask the right question, or nobody's doing this. What do I need to put into the select to actually get the character A.

            Richard DeemingR Offline
            Richard DeemingR Offline
            Richard Deeming
            wrote on last edited by
            #5

            Have you tried:

            ./text()[1]

            If that doesn't work, can you post your "tokenise" template?


            "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

            "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

            B 1 Reply Last reply
            0
            • Richard DeemingR Richard Deeming

              Have you tried:

              ./text()[1]

              If that doesn't work, can you post your "tokenise" template?


              "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

              B Offline
              B Offline
              bjmallon
              wrote on last edited by
              #6

              Richard, Sorry I haven't replied earlier. I went on leave the day you responded and have been... occupied since. I tried your suggestion, without success, although it has given me something to pursue. As requested, the tokenisation templates I gleaned from other forum sources a fair while ago are below. It worked well for what I was doing then, but it may not be the best for what I'm attempting now. Any advice would be appreciated.

              Richard DeemingR 1 Reply Last reply
              0
              • B bjmallon

                Richard, Sorry I haven't replied earlier. I went on leave the day you responded and have been... occupied since. I tried your suggestion, without success, although it has given me something to pursue. As requested, the tokenisation templates I gleaned from other forum sources a fair while ago are below. It worked well for what I was doing then, but it may not be the best for what I'm attempting now. Any advice would be appreciated.

                Richard DeemingR Offline
                Richard DeemingR Offline
                Richard Deeming
                wrote on last edited by
                #7

                OK, I think I've found the problem. Within the <xsl:for-each select="msxsl:node-set($Letters)/token">, the default context is the node-set returned from your "tokenise" template. When you try to resolve /Users, it's looking in that node set, rather than the source document. You need to capture the nodes from the source document that you want to process, and pass those to the template:

                <xsl:variable name="users" select="/Users" />

                <xsl:for-each select="msxsl:node-set($Letters)/token">
                <xsl:variable name="currToken" select ="./node()[1]"/>
                <xsl:call-template name="ListSurnameStartsWith">
                <xsl:with-param name="users" select="$users"/>
                <xsl:with-param name="character" select="$currToken"/>
                </xsl:call-template>
                </xsl:for-each>

                Update the template to:

                <xsl:template name="ListSurnameStartsWith">
                <xsl:param name="users" />
                <xsl:param name="character" select="''"/>

                <xsl:variable name="charMatch" select="$users/User\[starts-with(Surname, $character)\]"/>    
                <xsl:variable name="charCount" select="count($charMatch)"/>
                
                <xsl:if test="$charCount > 0">
                    <h2>
                        <a href="javascript:void(0)" class="dsphead" onclick="dsp(this)">
                            <span class="dspchar">+</span> <xsl:value-of select="$character"/> (<xsl:value-of select="$charCount"/>)
                        </a>
                    </h2>
                    <div class="dspcont">
                        <table border="1" cellpadding="1" cellspacing="1">
                            <tr>
                                <xsl:call-template name="HeadingRow"/>
                            </tr>
                            
                            <xsl:for-each select="$charMatch">
                                <xsl:sort select="Surname"/>
                                <xsl:call-template name="UserRow"/>
                            </xsl:for-each>
                        </table>
                    </div>
                </xsl:if>
                

                </xsl:template>


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                B 1 Reply Last reply
                0
                • Richard DeemingR Richard Deeming

                  OK, I think I've found the problem. Within the <xsl:for-each select="msxsl:node-set($Letters)/token">, the default context is the node-set returned from your "tokenise" template. When you try to resolve /Users, it's looking in that node set, rather than the source document. You need to capture the nodes from the source document that you want to process, and pass those to the template:

                  <xsl:variable name="users" select="/Users" />

                  <xsl:for-each select="msxsl:node-set($Letters)/token">
                  <xsl:variable name="currToken" select ="./node()[1]"/>
                  <xsl:call-template name="ListSurnameStartsWith">
                  <xsl:with-param name="users" select="$users"/>
                  <xsl:with-param name="character" select="$currToken"/>
                  </xsl:call-template>
                  </xsl:for-each>

                  Update the template to:

                  <xsl:template name="ListSurnameStartsWith">
                  <xsl:param name="users" />
                  <xsl:param name="character" select="''"/>

                  <xsl:variable name="charMatch" select="$users/User\[starts-with(Surname, $character)\]"/>    
                  <xsl:variable name="charCount" select="count($charMatch)"/>
                  
                  <xsl:if test="$charCount > 0">
                      <h2>
                          <a href="javascript:void(0)" class="dsphead" onclick="dsp(this)">
                              <span class="dspchar">+</span> <xsl:value-of select="$character"/> (<xsl:value-of select="$charCount"/>)
                          </a>
                      </h2>
                      <div class="dspcont">
                          <table border="1" cellpadding="1" cellspacing="1">
                              <tr>
                                  <xsl:call-template name="HeadingRow"/>
                              </tr>
                              
                              <xsl:for-each select="$charMatch">
                                  <xsl:sort select="Surname"/>
                                  <xsl:call-template name="UserRow"/>
                              </xsl:for-each>
                          </table>
                      </div>
                  </xsl:if>
                  

                  </xsl:template>


                  "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                  B Offline
                  B Offline
                  bjmallon
                  wrote on last edited by
                  #8

                  Richard, Thank you. That extra piece of understanding did the trick. Regards Brendan

                  1 Reply Last reply
                  0
                  Reply
                  • Reply as topic
                  Log in to reply
                  • Oldest to Newest
                  • Newest to Oldest
                  • Most Votes


                  • Login

                  • Don't have an account? Register

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • World
                  • Users
                  • Groups