• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 951
  • Last Modified:

XSLT Transformation

Hello,

I'am trying to do an XSLT transformation from XML to HTML, but when I look at the HTML afterwards it just shows the XML code in the view source.  I have a string[] with multiple paths and this is how I'am transforming them:

   foreach (string webPath in webPaths)
                {
                    WebClient write = new WebClient();
                    Stream str = write.OpenRead(webPath);
                    TextReader tw = new StreamReader(str);
                    processServer(tw);

                    xslTrans.Load("stats_transform.xslt");
                    xslTrans.Transform(webPath, globalWriter);

                     tw.Close();
                }

And here are my globals:
public static XslCompiledTransform xslTrans = new XslCompiledTransform();
public static XmlTextWriter globalWriter = new XmlTextWriter("stats.html", null);

When I look at the HTML, I expected it to be formatted by my XSLT rules, but all I get is the data between the tags, and not even the tag names are being displayed.

This is a sample of my XML:
  <?xml version="1.0" encoding="us-ascii" standalone="yes" ?>
- <Host xmlns="myServer">
- <Drive xmlns="C:\">
  <Capacity>31.21</Capacity>
  <AmtUsed>23.06</AmtUsed>
  <AmtNotUsed>8.16</AmtNotUsed>
  <PercentFree>26</PercentFree>
  </Drive>
</Host>

My XSLT is like this (not fully functional - just for testing so far):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
    <xsl:output method="html" />

    <xsl:template match="/">
            <table border="1" cellspacing="1" align="center">
                  <xsl:for-each select="Host/Drive">
                        <tr>
                              <td>
                              Capacity: <xsl:value-of select="Capacity"/>
                              </td>
                        </tr>
                        
                  </xsl:for-each>
                  
            </table>
      </xsl:template>
</xsl:stylesheet>

Anyone have any ideas?
0
igor92128
Asked:
igor92128
  • 4
  • 4
1 Solution
 
zc2Commented:
your xml has two namespaces declarations:
xmlns="myServer" and  xmlns="C:\"
you need explicitly declate them in the xsl :
xmlns:m="myServer" xmlns:c="C:\"         (the names instead of "m" and "c"  may be any)
and them use the same names as the tag prefixes:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    xmlns:m="myServer" xmlns:c="C:\">
    <xsl:output method="html" />
 
    <xsl:template match="/">
            <table border="1" cellspacing="1" align="center">
                  <xsl:for-each select="m:Host/c:Drive">
                        <tr>
                              <td>
                              Capacity: <xsl:value-of select="c:Capacity"/>
                              </td>
                        </tr>
                        
                  </xsl:for-each>
                  
            </table>
      </xsl:template>
</xsl:stylesheet>

Open in new window

0
 
igor92128Author Commented:
I just tried this and my HTML file is still just a bunch of numbers without tags or anything. So if I have xmlns in my XML file and they are different for each file, I'd need to build a pretty long XSLT file? I can't use for-each?

Maybe I'am not building my XML file correctly?

Iam declaring an xmlTextWriter: public static XmlTextWriter xwriter;

and using it like this:

xwriter = new XmlTextWriter(file, System.Text.Encoding.ASCII);
xwriter.WriteStartDocument(true);
xwriter.Formatting = Formatting.Indented;

xwriter.WriteStartElement("Host", gethostname());

foreach(DriveInfo d in alldrives)
{
xwriter.WriteStartElement("Drive", d.Name)
xwriter.WriteElementString("Capacity", d.Name, mycalculations);
...
...
xwriter.WriteEndElement();
}

            xwriter.WriteEndElement();
            xwriter.WriteEndDocument();
            xwriter.Close();
0
 
zc2Commented:
Did you intend to create the "Host" and "Drive" elements that way - with their value as a namespace?
It looks very odd...
(The second parameter  of WriteStartElement() creates a namespace declaration.)
Those values would be better stored in an named attribute using the WriteAttributeString() method.
Like:

xwriter.WriteStartElement("Host");
xwriter.WriteAttributeString("name", gethostname());
foreach(DriveInfo d in alldrives)
{
xwriter.WriteStartElement("Drive")
xwriter.WriteAttributeString("name", d.Name);
xwriter.WriteElementString("Capacity", d.Name, mycalculations);
...
...
xwriter.WriteEndElement();
}

Open in new window

0
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
igor92128Author Commented:
This is my XML file now, but I would need to get rid of the xmlns statements right?

<?xml version="1.0" encoding="us-ascii" standalone="yes" ?>
- <Host Name="myhost">
- <Drive Name="C:\">
  <Capacity xmlns="C:\">74.45</Capacity>
  <AmtUsed xmlns="C:\">61.12</AmtUsed>
  <AmtNotUsed xmlns="C:\">13.33</AmtNotUsed>
  <PercentFree xmlns="C:\">18</PercentFree>
  </Drive>
  </Host>
0
 
igor92128Author Commented:
Ok, I got the XML correct now I think:

<Host Name="myhost">
- <Drive Name="C:\">
  <Size>74.45</Size>
  <AmtUsed>61.12</AmtUsed>
  <AmtNotUsed>13.33</AmtNotUsed>
  <PercentFree>18</PercentFree>
  </Drive>
  </Host>

Will try to do the XSLT transform with this.
0
 
zc2Commented:
your last xml does not contain the Capacity element...
0
 
igor92128Author Commented:
I just renamed Capacity. Ok, I got it working but I have 1 more problem:

How do I select the value inside the tags for Host and Drive? Those values are blank in the result HTML file. All other values show up fine. Sample XSLT code is below.
<body>
				<p>
					Host: <xsl:for-each select="/Host"><br/>
						Drive: <xsl:for-each select="/Host/Drive"><br/>
							Capacity: <xsl:value-of select="Size"/><br/>
							Amount Used: <xsl:value-of select="AmtUsed"/><br/>

Open in new window

0
 
zc2Commented:
add a "@" before the attribute name to address its value, like:
Drive: <xsl:value-of select="@Name"/><br/>

The latest xslt is not quite correct.
You have two for-each loops: one for hosts and one for drives in each host.

But in your solution the inner loop will enumerate _all_ drives from all hosts.
The following enumerqates drives only in the current host:
<body>
  <p>
    <xsl:for-each select="Host">
      Host: <xsl:value-of select="@Name"/><br/>
       <xsl:for-each select="Drive">
         Drive: <xsl:value-of select="@Name"/><br/>
         Capacity: <xsl:value-of select="Size"/><br/>
         Amount Used: <xsl:value-of select="AmtUsed"/><br/>
       </xsl:for-each>
    </xsl:for-each>
  </p>
</body>

Open in new window

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now