Applying templates using XSLT on a simple XML

Jammerules
Jammerules used Ask the Experts™
on
I am a noob to XML and XSLT, so pardon me for such a question. Here is what I am trying to do. I have an XML file like this:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="xsltfile_ex2.xslt"?>
<Profiles>
    <Profile>
      <Salutation>Mr. </Salutation>  
      <FirstName>Barack</FirstName>
      <LastName>Obama</LastName>
      <ID>123</ID>
    </Profile>
</Profiles>

Open in new window


And I have an XSLT file like this:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:apply-templates select="Profiles/Profile"/>         
      </body>
    </html>
  </xsl:template>

  <xsl:template match="Profile"> 
      <tr>
          <xsl:apply-templates select="./FirstName"/>
      </tr>
  </xsl:template>

  <xsl:template match="FirstName">
    <tr bgcolor="red">
        <xsl:apply-templates select="./LastName"/>        
    </tr>
  </xsl:template>

  <xsl:template match="LastName">
    <tr bgcolor="red">
      <xsl:value-of select="./LastName"/>
    </tr>
  </xsl:template>
</xsl:stylesheet>
 

Open in new window


I am trying to get the Last Name from the XML. What is it that I am doing wrong? If someone also could please explain to me how the control flows in the above example (after correction), I'd appreciate that. Thanks!
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
IT Business Systems Analyst / Software Developer
Top Expert 2015
Commented:
The following will output the LastName (it will probably still need modification depending on exactly what you want to do)...

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <body>
        <xsl:apply-templates select="Profiles/Profile"/>         
      </body>
    </html>
  </xsl:template>

  <xsl:template match="Profile"> 
      <tr>
          <xsl:apply-templates select="./LastName"/>
      </tr>
  </xsl:template>

  <xsl:template match="FirstName">
    <tr bgcolor="red">
        <xsl:apply-templates select="./LastName"/>        
    </tr>
  </xsl:template>

  <xsl:template match="LastName">
    <tr bgcolor="red">
      <xsl:value-of select="."/>
    </tr>
  </xsl:template>
</xsl:stylesheet>

Open in new window


The changes and the reasons for them...

1) Within the Profile template you were selecting FirstNames and applying that template which was then trying to select LastNames. However, LastName is NOT a child of FirstName, is is next to it in the XML (ie, a sibling to it), and so there were no LastName elements to select. Therefore, I changed your Profile template to directly select/apply the LastName element (ie. to get the same output you could remove the FirstName from the XML and you could also remove the FirstName template from the XSLT (but I guessed that you will probably do something with that later)

2) Even if it were able to select a LastName element, when you are within the LastName template, the LastName element is already the current context, so your 'value-of' was trying to find a LastName element within the LastName element. So I changed the 'value-of' to select the current context (.) which is the current element being processed which IS already the LastName element, so it outputs to contents of that element.


Another thing that might explain the differences is if I craft the input file to MAKE it work with your XSLT. (I'm not saying that that is what you should do, just that it should help understand what you XSLT was doing)...

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="xsltfile_ex2.xslt"?>
<Profiles>
	<Profile>
		<Salutation>Mr. </Salutation>
		<FirstName>Barack
			<LastName>
				<LastName>Obama</LastName>
			</LastName>
		</FirstName>
		<ID>123</ID>
	</Profile>
</Profiles>

Open in new window


As you can see, there is now a LastName element INSIDE the FirstName element, so that the FirstName template has something to select and apply (at line 22 of your original XSLT). In addition, the LastName element has another LastName element inside so that (on line 28 of your original XSLT) the value-of has something to select and output the value of.

Author

Commented:
Hey McCarl,

I am reading your answer on my phone and pretty much "got" what I wanted and where I am going wrong. I will execute your code once I am home, but I am sure it works!. If I have further questions with this example, I hope you'd answer :) Thanks!!!
mccarlIT Business Systems Analyst / Software Developer
Top Expert 2015

Commented:
No worries, your welcome!
Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Author

Commented:
OK - check this code out:

XSLT:
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
  <xsl:output method="html"/>

  <xsl:template match="/">
    <html>
      <body>
        <table bgcolor ="grey" border="1">
          <xsl:apply-templates select="Profiles/Profile"/>
        </table>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="Profile"> 
      <tr>
          <xsl:apply-templates select="./LastName"/>          
      </tr>
  </xsl:template>

  <xsl:template match="LastName">     
          <xsl:value-of select="."/>
          <br/>
          <xsl:apply-templates select="./Occupations/Occupation"/>
  </xsl:template>

  <xsl:template match="Occupation">
    <xsl:value-of select="."/> 
  </xsl:template>
  
</xsl:stylesheet>
 

Open in new window

XML:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="xsltfile_ex2.xslt"?>
<Profiles>
    <Profile>
      <Salutation>Mr. </Salutation>  
      <FirstName>Barack</FirstName>
      <LastName>Obama
          <Occupations>
              <Occupation>USA Prez</Occupation> 
          </Occupations>
      </LastName>
      <ID>123</ID>
    </Profile>
</Profiles>

Open in new window

For some reason, while I just wanted the Last Name on row 1 of the table and Occupation on row 2 of the table, what I am getting is "Last Name AND Occupation" on row 1 and Occupation on row 2. Why?
mccarlIT Business Systems Analyst / Software Developer
Top Expert 2015

Commented:
> Why?

Because (on line 23) you are asking it to output the 'value of' the LastName element, which basically means everything in that element except markup. It doesn't matter that the occupation is within its own element, it is all still within the LastName element so when you ask for value-of select="." you get everything.

How to fix this? (Firstly, I just have to say that it is very strange to have the Occupation as part of the LastName element, I am hoping that you are doing this just for your own learning. If this was an actual XML file that needed processing, I would shoot the person who designed the schema! :)... But to fix this the way the XML currently is is easy. Change line 23 to...

<xsl:value-of select="text()"/>

Open in new window

Here we are specifically asking for the "text" node within the LastName element node and as such we only output "Obama", rather than before where we were asking it to output everything within the LastName element node.

Author

Commented:
... I would shoot the person who designed the schema!

Bwahaha!! Sorry, that unfortunate person is me that designed the schema. I, honestly, do not know how the Occupation ended up inside of LastName :). I will be more sensible in the future...lol. But, thanks so much for the explanation!

On a side note, I don't know if this is OK to ask, but is there a way I could communicate with you via the forum messenger (if there is such a thing)? That way when I have new questions posted on in here, you could try and answer it. It is a win win for the both of us. If not, I'd understand.
mccarlIT Business Systems Analyst / Software Developer
Top Expert 2015

Commented:
;) Glad to help.

No, there isn't really any way to do that. But if you post further questions in the same topic areas that you did this one, then I have notifications set up so that I get emailed when the new questions come in, so I will see anything that you post.

Author

Commented:
+1.

Looking forward to having a ton of my 'silly noob' questions to be answered by you!

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial