Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Get Path of Attribute 1

Status
Not open for further replies.

tshad

Programmer
Jul 15, 2004
386
US
Is there a way to get the path of an attribute?

In otherwords, if I have worked my way down to an attribute in some node, is there some way to get the path of that attribure or node name based on a current location.

I am trying to get a path to add to my translation of the path of a node.

Something like:

//RESPONSE/VMETHODS/SALES[@SequenceId="0"]/ADJUSTMENT[@_Type="Storage"]/@_Description

which I might get from something like:

<xsl:value-of select="path"/>

Thanks,

Tom
 
I know that I can get the path looking at "ancestor::*". But how can I get that returned?

If I have the following:

Code:
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="METHODS/COMPARISON">
        <xsl:with-param name="reportName" select="REPORT/@MajorFormType"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- Now we handle the other sections after the DATA section -->

  <xsl:template match="COMPARISON">
    <xsl:param name="reportName"/>
    <xsl:apply-templates>
      <xsl:with-param name="reportName" select="$reportName"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="SALE">
    <xsl:param name="reportName"/>
    <xsl:variable name="temp" select="../@ID"/>
    <xsl:value-of select="../@ID"/>    <!-- Works Here -->
    <xsl:for-each select="@*">
      <form>
        <var>
          <xsl:value-of select="$temp"/>
        </var>
        <ID>
          <xsl:value-of select="../../@ID"/>  <!-- Does Not Work Here -->
        </ID>
        <section>
          <xsl:text>0</xsl:text>
        </section>
        <formName>
          <xsl:value-of select="$reportName"/>
        </formName>
        <tagName>
          <xsl:value-of select="name()"/>
        </tagName>
        <value>
          <xsl:value-of select="."/>
        </value>
        <path>
          ancestor::*      <!--show as //REPSONSE/METHODS/COMPARISON/SALE -->
        </path>
      </form>
    </xsl:for-each>
    <xsl:apply-templates>
      <xsl:with-param name="reportName" select="$reportName"/>
    </xsl:apply-templates>
  </xsl:template>
 </xsl:stylesheet>

In the debugger, it might show ancester::*[4] which when expanded will show all the above nodes.

Is there a statement that will take the "ancester::*" and return the string as shown?

Thanks,

Tom
 
I tried to do the following:

Code:
        <path>
          <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="."/>
            <xsl:if test="position() != last()">
              <xsl:value-of select="."/>
            </xsl:if>
          </xsl:for-each>
        </path>

And the code seems to work but will not print out the value. If I look at the "." in the debugger, for each iteration - it shows the correct values (one of the node names in the path).

But when I look at the xml it created it just puts a bunch of spaces and line feed for these values and no node names.

Why is that?

Thanks,

Tom

 
Tom,

<xsl:value-of select="."/> is returning the value of the node, which for most of the nodes is whitespace. While the node name of the context node may be seen in the debugger, the node name is not the value of the context node. You might try select="local-name()" if I understand what you are trying to accomplish.

I think then you will find that the node names on the ancestor-or-self axis will appear in the opposite of your desired order. You will probably need to use recursion (such things eventually happen in the life of XSLT developers). Here are some recursion examples. After you work through an example or two, try writing your own. The called template would probably have two parameters, the current value of the string you wish to output and the next node to output (..). The called template would continue to concatenate the current node's information to the beginning of the string and call itself until the parent node is null, which means you are at the document root, and you can then output the string (with an xsl:value-of).

Sounds daunting if you are not familiar with recursion, but give it a try. If you are serious about using XSLT, cracking your first use of recursion is a major step in knowing how to use this tool.

Tom Morrison
Micro Focus
 
That does explain the spaces - thanks.

I did look further and did see information on recursion when I was trying to figure out how to return a value from a call-template.

I will look at the examples to get a better idea on how it works.

But I did find a way to do this which is similar to what you mentioned. This will get me the path with slashes between them in the correct order.

Code:
      <path>
        <xsl:for-each select="ancestor-or-self::*">
          <xsl:value-of select="name()" />
          <xsl:text>/</xsl:text>
        </xsl:for-each>
      </path>

Thanks,

Tom
 
Hmmm. That's not what I would expect.

The XSLT specification states that the ancestor-or-self axis should present the nodes in reverse document order. That is:
ancestor-or-self::*[1] is the context node,
ancestor-or-self::*[2] is the parent of the context node,
ancestor-or-self::*[3] is the grandparent of the context node,
...
ancestor-or-self::*[last()] is the document root.

Thus, I would expect your xsl:for-each loop to list the elements in reverse order.


Tom Morrison
Micro Focus
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top