tags:

views:

513

answers:

3

When I call this template I get the following results.

155IT Matches 155OO
155OO Matches 155OO
155PP

The XML I am processing does have three rows and those are the values, but why is the test returning true for the first two and false for the last one? How should I be doing the string comparison?

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
  <xsl:template name="ProofOfConcept">
      <xsl:param name="Lines"/>
      <xsl:param name="MainDeliveryCode"/>
      <xsl:choose>
        <xsl:when test="$Lines">
            <xsl:variable name="CurrentDeliveryCode" select="$Lines/DLVYLOCCD"/>
            <p>
            <xsl:choose>
                <xsl:when test=" $MainDeliveryCode = $CurrentDeliveryCode">
<xsl:value-of select="$CurrentDeliveryCode"/> Matches <xsl:value-of select="$MainDeliveryCode"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="$Lines"/> Fails <xsl:value-of select="$MainDeliveryCode"/>
                </xsl:otherwise>
            </xsl:choose>
            </p>
            <xsl:call-template name="ProofOfConcept">
                        <xsl:with-param name="Lines" select="$Lines[position() > 1]"/>
                        <xsl:with-param name="MainDeliveryCode" select="$MainDeliveryCode"/>
                     </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
        </xsl:otherwise>
      </xsl:choose>
  </xsl:template>

  <xsl:template match="/">
    <html>
        <head>
            <title></title>
        </head>
        <body>
            <xsl:call-template name="ProofOfConcept">
                <xsl:with-param name="Lines" select="data/Lines/LINE"/>
                <xsl:with-param name="MainDeliveryCode" select="data/header/DLVYLOCCD"/>
            </xsl:call-template>
        </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Sample data

 <?xml version="1.0"
 encoding="ISO-8859-1"
 standalone="yes"?> <data>   
 <header><DLVYLOCCD>155OO</DLVYLOCCD>
 </header>    <Lines>
       <LINE><DLVYLOCCD>155IT</DLVYLOCCD></LINE>
       <LINE><DLVYLOCCD>155OO</DLVYLOCCD></LINE>
       <LINE><DLVYLOCCD>155PP</DLVYLOCCD></LINE>
</Lines> </data>

Thanks for any advice.

A: 

I figured it out.

I need to change my test to

<xsl:when test="contains($MainDeliveryCode, $CurrentDeliveryCode" >

That solved the problem.

http://www.zvon.org/xxl/XSLTreference/Output/function_contains.html is the documentation for the function.

Jeremy
My recommendation would be to abandon your current XSLT and start over. ;) It might work, but the approach you take way to complicated and if it does not hurt you now, it will hurt you later.
Tomalak
Already did it after you showed me how to do it with selecting instead of recursion. I have even tested the new code with no loops and no recursion and it works perfectly.
Jeremy
+1  A: 

There are a few things wrong with your implementation. Most important, the expression:

<xsl:variable name="CurrentDeliveryCode" select="$Lines/DLVYLOCCD"/>

returns a node-set consisting of all the DLVYLOCCD elements, not just the current one as you seem to assume. Also, you shouldn't be using recursion to iterate. Use instead, in which case you will process the items one at a time.

Jim Garrison
+1 for "you shouldn't be using recursion to iterate".
Tomalak
I used recusrion in this case because I need stop on the first match. The goal is to find the first address for a location print it and stop processing so that I don't print it more than once.What expression would return just the current one?
Jeremy
+1  A: 

Here is a less painful version of your XSLT:

<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

  <xsl:template match="data">
    <html>
      <head>
        <title></title>
      </head>
      <body>
        <!-- this selects the matching LINE node(s), or nothing at all -->
        <xsl:apply-templates select="
          Lines/LINE[DLVYLOCCD = /data/header/DLVYLOCCD]
        " />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="LINE">
    <p>
      <!-- for the sake of the example, just output a copy -->
      <xsl:copy-of select="." />
    </p>
  </xsl:template>

</xsl:stylesheet>

gives (formatted result):

<?xml version="1.0" encoding="utf-8"?>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <p>
      <LINE><DLVYLOCCD>155OO</DLVYLOCCD></LINE>
    </p>
  </body>
</html>
Tomalak
Thanks but I needed to stop on the first match. I should have specified.
Jeremy
@Jeremy: Why would you want to output the three "fails" before the match, but not the three after it? Or do you *actually* want to output the match only?
Tomalak
I actually want to output the match only. I was outputting the fails as a diagnostic until I could devise a way to stop at the correct one.
Jeremy
You must try to stop thinking about XSLT in an iterative/imperative way. It is a declarative programming language - you should never iterate until you have what you are looking for, but simply *select* what you are looking for. I'll change my answer accordingly.
Tomalak
Do you have a good reference for how to select that I could use in the future?
Jeremy
You would need to learn XPath. There are plenty of web pages that provide tutorials, and XPath isn't *that* hard actually.
Tomalak
For XSLT/XPATH 1.0 I found Evan Lenz's "XSLT 1.0 Pocket Reference" (O'Reilly) to be a really good, inexpensive tutorial. It did a good job of communicating the essentials of declarative vs imperative style.
Jim Garrison