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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How to Display XML tags and values as an HTML 1

Status
Not open for further replies.

jedraw

Technical User
Feb 1, 2003
206
CA
I've done a little xml and xsl but am a relative newbie.
I have been unable to find a stylesheet to process an xml file and output the tagNames and tagValues in HTML.

I can get the node names with name() and the value with xsl:value-of ... but I would like to get the lowest level tagNames via the xsl. I'd like to be able to build html for a number of different xml files.


I'm trying to get something like:

Flights
Flight 1
Flight_Number: BA123
Origin : GLA
Destination : LHR
Carrier : British Airways
Date : 01/01/2002
.....
other flights

from xml as follows:
<Flights>
<Flight>
<Flight_Number>BA123</Flight_Number>
<Origin>GLA</Origin>
<Destination>LHR</Destination>
<Carrier>British Airways</Carrier>
<Date>01/01/2002</Date>
</Flight>
<Flight>
<Flight_Number>BA4234</Flight_Number>
<Origin>GLA</Origin>
<Destination>YOW</Destination>
<Carrier>British Airways</Carrier>
<Date>01/01/2002</Date>
</Flight>
</Flights>

TIA

jack
 
>get the lowest level tagNames
But, is it not name()? or if you like local-name() too which results the same.
[tt] <b><xsl:value-of select="name()" /></b>[/tt]
or[tt] <b><xsl:value-of select="local-name()" /></b>[/tt]
 
Thanks tsuji, but name() and local-name() seem to deal with the current node, not the "leaf" if you will.

I can't find anything that deals with the lowest level element...

jack
 
tsuji,

I have pursued your comment and have solved part of the issue. Thanks for your input.

This does output the leaf names and values. I'll have to do more to handle nodes within nodes, and the leaves within those nodes. Anyway this is a start.

Here's the output that gets produced(xsl is included below):

List of matching Flights

[blue]Flight[/blue]
Flight_Number: BA123
Origin: GLA
Destination: LHR
Carrier: British Airways
Date: 01/01/2002

[blue]Flight[/blue]
Flight_Number: BA4234
Origin: GLA
Destination: YOW
Carrier: British Airways
Date: 01/01/2002


Here is the xsl:
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
	<xsl:output method="html" indent="no"/>
	<xsl:template match="Flights">
		<html>
			<head>
				<title>Matching Request Flights</title>
			</head>
			<body>
				<h1>List of matching Flights </h1>
					<xsl:apply-templates select="Flight"/>
			</body>
		</html>
	</xsl:template>
		
		<!--  Templates -->
	<xsl:template match="Flight">
					<!-- Display Flight-->
					<tr><th><br/>
					<b><font color="blue"><xsl:value-of select="local-name()"/></font></b>
					</th></tr>
					 <table border="0">
					    <xsl:apply-templates />
					</table>
	</xsl:template>			
	 <xsl:template match="Flight/*">
							<tr><td><b><xsl:value-of select="local-name()"/>:</b></td>
							<td><xsl:value-of select="."/></td></tr>
    </xsl:template>
</xsl:stylesheet>
 
> I'll have to do more to handle nodes within nodes, and the leaves within those nodes.

If you miss some functionality to get there, this example might help you get further. It produces exactly what you show in your first post.
[tt]
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="<xsl:template match="/">
<html>
<body>
<xsl:for-each select="//*">
<p>
<xsl:for-each select="ancestor::*[position()]">
<xsl:text>&#xa0;&#xa0;&#xa0;&#xa0;</xsl:text>
</xsl:for-each>
<xsl:if test="count(ancestor::*) &lt; 2">
<xsl:value-of select="local-name()" />
</xsl:if>
<xsl:if test="not(count(ancestor::*) &lt; 2)">
<b><xsl:value-of select="local-name()" /></b>
</xsl:if>
<xsl:if test="count(ancestor::*) = 1">
<xsl:text>&#xa0;</xsl:text>
<xsl:value-of select="count(preceding-sibling::*)+1" />
</xsl:if>
<xsl:if test="text()">
<b><xsl:text>&#xa0;:&#xa0;</xsl:text></b><xsl:value-of select="text()" />
</xsl:if>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
[/tt]
ps I use liberally archaic html style-related tags for the ease of exposition. Feel free to make it more to the modern standard.
 
tsuji,

Thank you. This not only works for my example, but I found that I can take other, more complex, xml structures and get a complete "dump" of TagNames and values without having to know or supply any explicit node names.

This worked perfectly. However, after I ran this xsl against some other xml, I started to see  characters instead of the spaces (&#xa0;). The spaces were there when I first ran your xsl.

I have reloaded your xsl into xmlspy, but I now get the  characters everywhere? Any idea of what may be causing, or has caused this?

jack
 
I have inserted a
<xsl:eek:utput method="html"></xsl:eek:utput> statement
and now everything is working again. Not sure how things were working, then just seemed to go crazy with the As.

jack
 
jedraw, I have not had time yet to look into it. But you've discovered the effect of that line which makes it more robust. That's how thing work together. Thanks for the feedback. I sure will look into it when I have a chance to build sample page showing the abberrations you'd described. Thanks!
 
This will work with any XML document (also outputs attributes):
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <html>
      <head>
        <title>My XML</title>
      </head>
      <body>
        <xsl:call-template name="DisplayTree">
          <xsl:with-param name="node" select="*"/>
          <xsl:with-param name="indent" select="0"/>
        </xsl:call-template>
      </body>
    </html>
  </xsl:template>
  <xsl:template name="DisplayTree">
    <xsl:param name="node"/>
    <xsl:param name="indent"/>
    <div style="margin-left: {$indent}px;">
      <span>
        <xsl:if test="$node/text()">
          <xsl:attribute name="style">font-weight: bold;</xsl:attribute>
        </xsl:if>
        <xsl:value-of select="name($node)"/>
      </span>
      <xsl:if test="$node/text()">
        <xsl:text>: </xsl:text>
        <xsl:value-of select="$node/text()"/>
      </xsl:if>
      <xsl:for-each select="$node/@*">
        <span style="color: blue;">
          <xsl:text> @</xsl:text>
          <xsl:value-of select="name(.)"/>
          <xsl:text>: </xsl:text>
          <xsl:value-of select="."/>
        </span>
      </xsl:for-each>
    </div>
    <xsl:for-each select="$node/*">
      <xsl:call-template name="DisplayTree">
        <xsl:with-param name="node" select="."/>
        <xsl:with-param name="indent" select="$indent + 20"/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Jon

"I don't regret this, but I both rue and lament it.
 
Jon,

Thank you. I have just tried your xsl and it's great!

I'm surprised by the responses that I've gotten. They all work, and they all seem quite different. Guess that's a message for xml/xsl -- many ways to "skin the cat".

I'll spend some time to understand the meaning/function of
<xsl:with-param name="node" select="*"/>
<xsl:with-param name="indent" select="0"/>

and the
<span>
<xsl:if test="$node/text()">
<xsl:attribute name="style">font-weight: bold;</xsl:attribute>
</xsl:if>
<xsl:value-of select="name($node)"/>
</span>


Thanks again.

jack
 
Code:
<xsl:with-param name="node" select="*"/>
<xsl:with-param name="indent" select="0"/>
This initialises the recursion with the root element (* means children of current element) as node parameter and indent of 0. Each level of the recursion adds a level of indentation.
Code:
<span>
  <xsl:if test="$node/text()">
    <xsl:attribute name="style">font-weight: bold;</xsl:attribute>
  </xsl:if>
  <xsl:value-of select="name($node)"/>
</span>
This just says if the current node has a text node as a child, then make the text bold. Shout if you need any more help.

Jon

"I don't regret this, but I both rue and lament it.
 
Jon

Thanks for the explanation, it really helps.

Do you have a site or tutorials you recommend for learning XML/XSL etc?

I'm using XMLSpy 2006 Home(free version)
to work thru some of the things I'm trying to do.

The purpose of my effort is to review/QA some xml responses to a few web services (Soap + XML).

I'm trying to check that the appropriate fields are valued in various circumstances. So that's why I'm looking at tagName, tagValue within the XML hierarchy.

I've had a few responses. The xsl from you and tsuji both deal with all of the pieces without knowing the actual data names.

In my approach that did do some things, I worked with each of the tagNames -- which I can see requires too much custom programming.

Your approach works with all the hierarchy and complex types I've tried. It's very generic. I think it makes an excellent utility tool.

jack
 
I use


all the time, especially the XSL element ref:


and the XPath function ref:


apart from that, google normally provides an answer, but then you have to know what you're looking for. Answering problems on this forum always teaches you new things and keeps your skills sharp.

Jon

"I don't regret this, but I both rue and lament it.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top