p2p.wrox.com Forums

p2p.wrox.com Forums (http://p2p.wrox.com/index.php)
-   XSLT (http://p2p.wrox.com/forumdisplay.php?f=86)
-   -   xsl question (http://p2p.wrox.com/showthread.php?t=33367)

bluisana September 13th, 2005 06:58 PM

xsl question
 
I am having a problem making an xslt template to pase a small xml file I have.

I am passing the xslt file one parameter. I want to use this parameter to match a node that has the parameter in it then loop through its children.

the xml file looks like this.

<HEADER>
    <LINK name="Education">
        <TITLE>HighSchool</TITLE>
        <URL>/Intrests.aspx</URL>
        <TITLE>Bachelors</TITLE>
        <URL>/Projects.aspx</URL>
        <TITLE>Masters</TITLE>
        <URL>/Projects.aspx</URL>
        <TITLE>Certifications</TITLE>
        <URL>/Projects.aspx</URL>
    </LINK>
    <LINK name="Home"></LINK>
    <LINK name="Interests"></LINK>
    <LINK name="Contact"></LINK>
    <LINK name="Project"></LINK>
    <LINK name="Work"></LINK>
    <LINK name="About Site"></LINK>
</HEADER>

I want to use my passed in parameter to match the name attribute of the link node and loop through the TITLE and URL elements within that node.

I was trying something like this without much luck.

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">


    <xsl:param name="LINK" select="Education"></xsl:param>
    <xsl:for-each select="//HEADER/LINK/@name">
        <xsl:if test="@name=$LINK">
        <xsl:for-each select="//HEADER/LINK/TITLE">
        <a>
      <xsl:attribute name="HREF">test<xsl:value-of select="TITLE"/>test</xsl:attribute>
      <xsl:value-of select="@name" />

      </a>
        </xsl:for-each>
        </xsl:if>
     </xsl:for-each>

</xsl:template>

</xsl:stylesheet>

I know the loops above don't exactly make sense right now because I have been changing them so much but I can't get anything I try to work. I am setting the parameter "LINK" above to Education just for testing purposes.

Is there a better way to do this istead of using 2 loops?

Any help would be much apreciated.



joefawcett September 14th, 2005 02:27 AM

Try to avoid using // in paths, it's an expensive process to select all nodes in the document when you know what level they are at anyway.
Your main problem is that your param defaults to Education, i.e. the XSLT tries to evaluate Education as a node test not a string, you need 'Education'. Your search logic can also be simplified, try this:
Code:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="LINK" select="'Education'" />

  <xsl:template match="/"> 
    <xsl:apply-templates select="HEADER/LINK[@name = $LINK]" />
  </xsl:template>

  <xsl:template match="LINK">
    <h3><xsl:value-of select="@name" /></h3>
    <xsl:apply-templates select="TITLE" />
  </xsl:template>

  <xsl:template match="TITLE">
    <a href="{following-sibling::URL[1]}"><xsl:value-of select="." /></a> 
  </xsl:template>
</xsl:stylesheet>

I think your XML would be easier to manage if you had thius sort of thing:
Code:

  <LINKS name="Education">
    <LINK><TITLE>HighSchool</TITLE>
      <URL>/Intrests.aspx</URL>
    </LINK>
    <LINK><TITLE>Bachelors</TITLE>
      <URL>/Projects.aspx</URL>
    </LINK>
    <LINK><TITLE>Masters</TITLE>
      <URL>/Projects.aspx</URL>
    </LINK>
    <LINK><TITLE>Certifications</TITLE>
      <URL>/Projects.aspx</URL>
    </LINK>
  </LINKS>


--

Joe (Microsoft MVP - XML)

mhkay September 14th, 2005 03:15 AM

You haven't understood the concept that xsl:for-each changes the context node, and relative path expressions start from the context node.

    <xsl:for-each select="//HEADER/LINK/@name">

This means that the context node is now an attribute, the @name attribute. (Also note, HEADER is the outermost element of your document, so you don't need to search the whole document to find it. Use /HEADER rather than //HEADER).

        <xsl:if test="@name=$LINK">

@name is a relative path expression, it looks for an attributes of the context node called name. But attributes don't have attributes, so it won't find one. You want test=". = $LINK".

        <xsl:for-each select="//HEADER/LINK/TITLE">

This is a so-called "absolute path expression". It doesn't start from the context node, it starts from the root. So you're selecting all the TITLE elements, not just the one for the selected LINK. You want the TITLEs of the LINK that's the parent of the selected attribute: select="../TITLE". Or most people would do it like this:

<xsl:for-each select="/HEADER/LINK[@name=$LINK]">
        <a>
      <xsl:attribute name="HREF">test<xsl:value-of select="TITLE"/>test</xsl:attribute>
      <xsl:value-of select="@name" />

      </a>
 </xsl:for-each>

Go back to the spec or your favourite reference book, and reread the section about the context node.



Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference

bluisana September 14th, 2005 09:19 AM

Thanks alot,

After reading your comments I decided to go through the w3schools xslt refrence. Everything makes much more sense now.


bluisana September 14th, 2005 01:22 PM

I still am not able to get exactly what I want.

I did change my xml format to the suggestion from above and I tried many variations on the xsl that both of you guys posted. The xsl that you guys posted only returned the top link after the LINKS element with the matching name attribute. I want to display all of the LINK elements.

It seemed logical to me that this would do exactly what I want.

 <xsl:template match="/">
    <html>
    <body>
    <xsl:apply-templates select="HEADER/LINKS[@name = $LINK]" />
    <xsl:for-each select="LINK">
    <a>
      <xsl:attribute name="HREF"><xsl:value-of select="TITLE"/>test
      </xsl:attribute>
      </a>
      </xsl:for-each>
    </body>
     </html>
  </xsl:template>

The xsl above sends out all of the TITLES and all of the URLS and it doesn't format them into html href links.

Waht is going on here?


bluisana September 14th, 2005 01:48 PM

I finally got something to do exactly what I was looking for. Thanks for all the help.


mhkay September 14th, 2005 05:18 PM

The root node "/" can either have a HEADER child or a LINK child but it can't have both. You've got an apply-templates that assumes it has a HEADER child, and a for-each that assumes it has a LINK child.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference

joefawcett September 15th, 2005 01:34 AM

Quote:

quote:Originally posted by bluisana
 I still am not able to get exactly what I want.

The xsl that you guys posted only returned the top link after the LINKS element with the matching name attribute. I want to display all of the LINK elements.
Are you sure about this? I tested the XSLT and it returned all the links for a section given the original format.

--

Joe (Microsoft MVP - XML)


All times are GMT -4. The time now is 12:46 PM.

Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.