Click to See Complete Forum and Search --> : Output html that was inside the xml file


Verdagon
04-01-2009, 10:44 PM
Hi everyone, lets say I have this xml file:

<?xml version="1.0"?>
<!DOCTYPE HTML>
<?xml-stylesheet type="text/xsl" href="tiles.xsl" ?>
<v:page xmlns:v="http://verdagon.net/">
<v:head />
<v:contents>
<ul>
<li>iPhone programming</li>
<li>Nobilia, an online game</li>
<li>Surviving college</li>
</ul>
</v:contents>
</v:page>

and I have this template:
<xsl:template match="/v:page/v:contents">
<body>
<div id="contents">
<xsl:apply-templates />
</div>
</body>
</xsl:template>

The <ul> list gets converted completely to text! My guess is that xsl thinks that ul and li are xsl elements, and then it doesnt recognize them so it ignores them. How do I tell it that these elements are html, and should be output?

Also, I may put some v:floatingPortrait elements (which show a floated image) inside the v:contents tag, so just spitting out the contents of the v:contents tag wouldn't be a very good solution...

If I could tell it that anything with no namespace is just html, that would be perfect, but I've been googling for hours and I can't find it.

Thanks for your time in advance,

- Evan

Charles
04-02-2009, 06:32 AM
It's something like:<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy/>

Verdagon
04-02-2009, 12:02 PM
Ah, that's much closer to the result than I've gotten. However, there's still one problem... I get a <page> element in my output, supposedly because I didn't explicitly define a template that matches /v: page. Is there a way to avoid this without explicitly defining every element like that?

Charles
04-02-2009, 12:05 PM
Try <xsl:template match="v:*">
<xsl:apply-templates/>
</xsl:template>

Verdagon
04-02-2009, 02:42 PM
Wow, that worked very nicely! Thanks for your help.

Another thing that I think is related though, if you could take a look at it...

<xsl:template match="v:hovermap">
Inside hovermap end!
<div>
Inside div begin!
<xsl:apply-templates />
Inside div end!
</div>
Inside hovermap begin!
</xsl:template>

<xsl:template match="v:hover-area">
hover area!
</xsl:template>

<xsl:template match="/v:page/v:contents">
<body>
<div id="pageContainer">
...

<v:hovermap id="linksImage" mapID="linksMap">
<v:hover-area color="purple" href="aboutMe.xml" coords="511,34, 663,67, 654,108, 502,75, 511,34" />
<v:hover-area color="green" href="home.xml" coords="655,30, 784,97, 766,130, 638,63, 655,30" />
<v:hover-area color="red" href="contact.xml" coords="559,113, 728,97, 732,132, 563,149, 559,113" />
<v:hover-area color="orange" href="portfolio.xml" coords="626,146, 646,114, 795,205, 776,238, 626,146" />
<v:hover-area color="blue" href="login.xml" coords="654,190, 685,160, 809,285, 779,315, 654,190" />
</v:hovermap>
</div>
</body>
</xsl:template>

The v:hovermap and contained v:hover-area elements aren't being transformed by their templates; instead, the output is:
<hovermap mapID="linksMap" id="linksImage">
<hover-area coords="511,34, 663,67, 654,108, 502,75, 511,34" href="aboutMe.xml" color="purple"></hover-area>
<hover-area coords="655,30, 784,97, 766,130, 638,63, 655,30" href="home.xml" color="green"></hover-area>
<hover-area coords="559,113, 728,97, 732,132, 563,149, 559,113" href="contact.xml" color="red"></hover-area>
<hover-area coords="626,146, 646,114, 795,205, 776,238, 626,146" href="portfolio.xml" color="orange"></hover-area>
<hover-area coords="654,190, 685,160, 809,285, 779,315, 654,190" href="login.xml" color="blue"></hover-area>
</hovermap>
...as if it was never transformed.

Any idea what's going on? I did some research and found that call-template might need to be involved, but I really hope it won't be needed, because it's such a simple need. Can templates not contain elements that use other templates?

Thanks for your time! I really appreciate it.

- Evan

Charles
04-02-2009, 02:53 PM
I'm a bit confused about what is going on, without seeing both documents in whole. But it looks like the stylesheet is outputting exactly what you are asking it to output.

Or put another way as for this fragment, What does the input look like and what do you want the output to look like?

Verdagon
04-02-2009, 07:11 PM
Sorry, looks like I got so caught up in the complexity and committed one of the cardinal sins of discussion boards: not giving a concrete repro.

Here's the xsl:
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:v="http://verdagon.net/">
<xsl:output method="html" />

<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>

<xsl:template match="v:*">
<xsl:apply-templates />
</xsl:template>

<xsl:template match="v:page">
<html>
<body>
<xsl:apply-templates />
<v:footer />
</body>
</html>
</xsl:template>

<xsl:template match="v:footer">
<div class="myfooter">
Page made by Evan
</div>
</xsl:template>

</xsl:stylesheet>

and here's the xml that uses that stylesheet:
<?xml version="1.0"?>
<!DOCTYPE HTML>
<?xml-stylesheet type="text/xsl" href="test.xsl" ?>
<v:page xmlns:v="http://verdagon.net/">
<p>Hello!</p>
</v:page>

and here's the output:
<html>
<body>
<p>Hello!</p>
<footer></footer>
</body>
</html>

Isn't that weird? I expected something like this:
<html>
<body>
<p>Hello!</p>
<div class="myfooter">
Page made by Evan
</div>
</body>
</html>

So why didn't it replace the <v:footer /> with <div class="myfooter">Page made by Evan</div>? If I moved the <v:footer /> element into the xml, it does the replacement fine, so my real question is:

Why isn't the v:footer element expanded when I call it from inside a template?

Thanks for all your help, seriously :)

- Evan

dmboyd
04-02-2009, 09:59 PM
XSLT is used to transform an XML (input) document. It doesn't apply the rules recursively. The following two are equivalent in XSLT:
<xsl:template match="/">
<html lang="en">
<!-- I'm a comment in the XSLT document, not in the result document. -->
</html>
</xsl:template>

<xsl:template match="/">
<xsl:element name="html">
<xsl:attribute name="lang">
<xsl:text>en</xsl:text>
</xsl:attribute>
<!-- I'm a comment in the XSLT document, not in the result document. -->
</xsl:element>
</xsl:template>

Simply put, if you have an element that isn't in the XSLT namespace, it is interpreted as an element to be included in the transformation. Notice that I said "elements" rather than "elements, attributes, comments, etc." One thing that puzzles me is why <footer></footer> is outputted instead of <v:footer></v:footer>. Then again, if it is HTML that is being outputted, there is no concept of namespaces, which might explain it.

Verdagon
04-03-2009, 12:18 AM
I see. Is there a way to manually transform it? maybe something like this?

<xsl:evaluate>
<v:footer />
</xsl:evaluate>

My research has told me that I can use xsl:call-template in this case, like so:

<xsl:call-template name="v:footer" />

Except I need to call it 4 times, each with 3 arguments; this will lead to 20 lines of code if i use xsl:call-template, something like:

<xsl:call-template name="v:footer">
<xsl:with-param name="line" value="Made by Evan" />
<xsl:with-param name="color" value="red" />
<xsl:with-param name="align" value="center" />
</xsl:call-template>
<xsl:call-template name="v:footer">
<xsl:with-param name="line" value="Evan is cool" />
<xsl:with-param name="color" value="yellow" />
<xsl:with-param name="align" value="center" />
</xsl:call-template>
<xsl:call-template name="v:footer">
<xsl:with-param name="line" value="Seriously" />
<xsl:with-param name="color" value="green" />
<xsl:with-param name="align" value="center" />
</xsl:call-template>
<xsl:call-template name="v:footer">
<xsl:with-param name="line" value="Evan rocks" />
<xsl:with-param name="color" value="blue" />
<xsl:with-param name="align" value="center" />
</xsl:call-template>

So you see, the xsl:call-template and xsl:with-param elements bloat my code severely. I would like to be able to just evaluate this in the XSL, which is much nicer and makes a bit more sense:

<v:footer line="Made by Evan" color="red" align="center" />
<v:footer line="Evan is cool" color="yellow" align="center" />
<v:footer line="Seriously" color="green" align="center" />
<v:footer line="Evan rocks" color="blue" align="center" />

I would have thought XSL would keep running my templates on its output recursively until there are no xsl elements left. It's a shame that we can't do that, but is there a way to simulate it and tell it to run the transforms manually, such as this?

<xsl:evaluate>
<v:footer line="Made by Evan" color="red" align="center" />
<v:footer line="Evan is cool" color="yellow" align="center" />
<v:footer line="Seriously" color="green" align="center" />
<v:footer line="Evan rocks" color="blue" align="center" />
</xsl:evaluate>

I really appreciate the help you're giving me. I'm excited about mastering xsl =)

- E

dmboyd
04-03-2009, 12:26 AM
Well, v:footer would need to go in the XML file where it is necessary. Then you could use XSL to transform it properly.

Verdagon
04-03-2009, 01:05 AM
Yeah, but if each page has the same footer, then I wish I could put it in the XSL stylesheet; seems like it would be the logical thing to do.

Am I right in thinking that this functionality is sorely missing from XSL? I would think there's another way to do this =(

- E

dmboyd
04-03-2009, 01:08 AM
You could make use of XInclude (assuming you're transforming the XML through a programming language or something other than a Web browser that supports XSLT), but you would still need to include the XInclude line in each XML file. It really isn't any different than something like PHP, C, Java or even JavaScript where you need to include any file that you wish to use.