XSLT: Transforming into non-xml content? - html

Is it possible to use XSLT to transform XML into something other than XML?
e.g. i want the final non-xml content:
<Content>
<image url="file1.png">
<image url="file2.png">
...
<image url="filen.png">
<EndContent>
You'll notice this document is not xml (or even html), but it does have what we would call <elements>.
Is it possible, using XSLT, to generate non-xml output?
Another example of non-xml output might be:
<HTML>
<BODY>
<IMG src="file1.png"><BR>
<IMG src="file2.png"><BR>
...
<IMG src="filen.png"><BR>
</BODY>
</HTML>
You'll notice this document is HTML, because in HTML IMG and BR tags are forbidden from having a closing tag. This contrasts with xhtml (the reformulation of HTML using xml) where all elements are required to have a closing tag (because in xml every tag must be closed).
Another example of non-xml output might be:
INSERT INTO Documents (Filename) VALUES ('file1.png')
INSERT INTO Documents (Filename) VALUES ('file2.png')
...
INSERT INTO Documents (Filename) VALUES ('file3.png')
i can make up any source xml i like, but one example might be:
Source xml:
<DocumentStore>
<Document type="image">file1.png</Document>
<Document type="image">file2.png</Document>
<Document type="image">filen.png</Document>
</DocumentStore>
Or perhaps:
<Profiles>
<User avatar="file1.png" />
<User avatar="file2.png" />
<User avatar="filen.png" />
</Profiles>

You can use <xsl:output> to specify the output format, which doesn't have to be xml, see this reference page.
However, if you are outputting html, no modern browser should complain even if you do put the closing tags, so using your example above, i believe all browser should be ok with :-
<HTML>
<BODY>
<IMG src="file1.png"></IMG><BR></BR>
<IMG src="file2.png"></IMG><BR></BR>
...
<IMG src="filen.png"></IMG><BR></BR>
</BODY>
</HTML>
So not too sure why you don't want to put the closing tag, unless i'm missing something.
Update: Added example of non xml output
Given this stylesheet:-
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/filenames">
<xsl:for-each select="filename">
INSERT INTO Documents (Filename) VALUES ('<xsl:value-of select="." />')
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
and this input xml:-
<?xml version="1.0" encoding="UTF-8"?>
<filenames>
<filename>file1.png</filename>
<filename>file2.png</filename>
<filename>file3.png</filename>
</filenames>
You get output like this:-
INSERT INTO Documents (Filename) VALUES ('file1.png')
INSERT INTO Documents (Filename) VALUES ('file2.png')
INSERT INTO Documents (Filename) VALUES ('file3.png')

No matter how you create your IMG tags,
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:element name="IMG">
<xsl:attribute name="src">file1.png</xsl:attribute>
</xsl:element>
<IMG src="file2.png"></IMG>
<IMG src="filen.png"/>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
The output method "html" will cause the IMG tags to not be closed.
<HTML>
<BODY><IMG src="file1.png"><IMG src="file2.png"><IMG src="filen.png"></BODY>
</HTML>

Yes, you can, by using the xsl:output element in your stylesheet.

Related

Get XML atribute using XSLT for a href on HTML

I have come across this problem while doing a home project and I honestly do not know how to solve it.
The goal is, using XSLT, get a certain attribute from my XML and add it to href.
<Video videoID="v0001" imageLink="IMG/VIDEO_IMG/v0001_img.jpg"/>
Then, by applying the XSLT, that looks kinda like this:
<xsl:template match="/">
<xsl:for-each select="Video"/>
<a href="X">
<img src="Y"/>
</a>
</xsl:template>
where X is the imageLink from the XML and Y is gonna be the local link to the XHTML page of that single video.
<!--The goal is getting something like this after using XSLT-->
<a href="VIDEOS/video_v0001.xhtml">
<img class="User" src="../IMG/VIDEO_IMG/v0001_img.png" alt="VideoImage"/>
</a>
Assume that your XML input is:
<?xml version="1.0" encoding="UTF-8"?>
<Videos>
<Video videoID="v0001" imageLink="IMG/VIDEO_IMG/v0001_img.jpg"/>
<Video videoID="v0002" imageLink="IMG/VIDEO_IMG/v0002_img.jpg"/>
</Videos>
Then the XSLT script performing your task can be:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xhtml" doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system= "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"
encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="Videos/Video">
<a href="VIDEOS/video_{#videoID}.xhtml">
<img class="User" src="../{substring-before(#imageLink, '.')}.png"
alt="VideoImage"/>
</a>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:transform>
As you can see, there should be 2 Attribute Value Templates ({...}),
one drawing the content from source videoID attribute and the other -
from imageLink.
In the second case the content to be copied is limited to the part
before the dot, because in this case file name extension is different.
Note that I used method="xhtml" and both doctype attributes for XHTML
page. Maybe in your case they should be different.
For a working example see http://xsltransform.net/jxWYjVH/1
To get a full HTML page, add <head> tag and other HTML stuff, according
to your needs, e.g. a stylesheet for User class.

Incorrect display when an image is added to XML

This is my XML:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="staff.xsl"?>
<st>
<employee>
<name>
<firstname>Clay</firstname>
<lastname>Hansen</lastname>
</name>
<jobtitle>Professor</jobtitle>
<department>Department: Communication and Marketing</department>
<office>Office: CH-H 111</office>
<phone>Phone: (847)257-1234</phone>
<email>Email: clay.h#abc.com</email>
<profile>
<html xmlns="http://www.w3.org/1999/xhtml">
<img src="C:\Users\username\Desktop\im.jpg" /> <!-- added closing tag by edit -->
</html>
</profile>
</employee>
</st>
here is my xml and extrenal xsl code. When I add an image, it does not display my data in tabular form. It displays it like words in a sentence. How can I solve it?
This is because xsl:value-of returns the concatenated text nodes of a element's subtree with the markup removed (in your case there is none). You could copy the img node like this:
<xsl:for-each select="employee">
<td>
<xsl:copy-of select="profile//xhtml:img"></xsl:copy-of>
</td>
</xsl:for-each>
Note, that you have to declare the xhtml namespace in your stylesheet to process the img nodes:
xmlns:xhtml="http://www.w3.org/1999/xhtml"

XML to XSL transformation

I am new to XML. I am trying to convert the following XMl file
<?xml version="1.0"?>
<parent original_id="OI123" id="I123">
<custompanel panel="cp"></custompanel>
</parent>
into the following HTML
<html>
<body><div xmlAttribute="{"original-id":"OI123","id":"I123"}">
<p xmlAttribute={"panel":"cp"}/>
</div>
</body>
</html>
XML tag <parent> should be converted to <div> and <custompanel> should be converted to <p> tag.
I have read the XSTL documentation from W3CSchool but still I am not exactly sure how to approach the problem.Can anyone help me with it?
The custom attribute needs to be stored in xmlAttribute as JSONObject.
After a quick research of the correct syntax I came up with this.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
method="xml"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
indent="yes"
encoding="utf-8" />
<xsl:template match="parent">
<html>
<body>
<div xmlAttribute="{{'original-id':'{#original_id}','id':'{#id}'}}">
<xsl:apply-templates />
</div>
</body>
</html>
</xsl:template>
<xsl:template match="custompanel">
<p xmlAttribute="{{'panel':'{#panel}'}}" />
</xsl:template>
</xsl:stylesheet>
The tricky part is espacing the {} for the JSON, which we build ourselves. You need two curly braces {{ to have a literal one. Also you need to use single quotes ' inside the attributes as double quotes would be escaped to ". You can access attributes with the #foo selector, but now you need to use actual {} to make the processor recognize it should do something.
I guess that your actual file has more than one <parent>. In that case you need to have a root element around it, and you need to adjust the XSLT. Add another <xsl:template match="/"> and move the HTML frame there.

XSLT transform removes HTML elements from mixed-content

Is it possible for XSLT preserve anchors and other embedded HTML tags within XML?
Background: I am trying to convert an HTML document into XML with an XSL stylesheet using XSLT. The original HTML document had content interspersed with anchor tags (e.g. Some hyperlinks here and there). I've copied that content into my XML, but the XSLT output lacks anchor tags.
Example XML:
<?xml version="1.0" ?>
<observations>
<observation>Hyperlinks disappear.</observation>
</observations>
Example XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/html">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:template match="/observations">
<html>
<body>
<xsl:value-of select="observation"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Output:
<html xmlns="http://www.w3.org/1999/html">
<body>Hyperlinks disappear.</body>
</html>
I've read a few similar articles on stackoverflow and checked out the Identity transform page on wikipedia; I started to get some interesting results using xsl:copy-of, but I don't understand enough about XSLT to get all of the words and tags embedded within each XML element to appear in the resulting HTML. Any help would be appreciated.
Write a separate template to match a elements, copy their attributes and content.
What is wrong with your approach? In your code,
<xsl:value-of select="observation"/>
simply sends to the output the string value of the observation element. Its string value is the concatenation of all text nodes it contains. But you need not only the text nodes in it, but also the a elements themselves.
The default behaviour of an XSLT processor is to "skip" element nodes, because of a built-in template. So, if you do not mention a in a template match, it is simply ignored and only its text content is output.
Stylesheet
Note: This stylesheet still relies on the default behaviour of the XSLT processor to some extent. The order of events will resemble the following:
The template where match="/observations" is matched. It adds html
and body to the output. Then, a template rule must be found for the
content of observations. A built-in template matches observation,
does nothing with it, and looks for a template to process its content.
For the a element, the corresponding template is matched, with
copies the element and attributes. Finally, a built-in template copies
the text nodes inside observation and a.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/observations">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="a">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<html>
<body>Hyperlinks disappear.
</body>
</html>

How to get a value from a JavaScript in XSLT?

I have the following XML and XSLT to transform to HTML.
XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<te>t1</te>
</root>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="root">
<html>
<div>
<xsl:variable name="name1" select="te" />
**
<xsl:value-of select="CtrlList['$name1']" />
**
</div>
<script language="javascript">var List={
"t1":"test"
}</script>
</html>
</xsl:template>
</xsl:stylesheet>
So my objective is get the value of "te" from the XML and map it with the JavaScript object "List" and return the value test while transforming with the XSLT. So i should get the value test as output.
Can anyone figure out what wrong in the XSLT.
When you look at your XSLT, it may seem like there is JavaScript there, but all XSLT sees is that it is outputing an element named "script", with an attribute "language", which contains some text. It is also worth noting that xsl:value-of is used to get the value from the input document, but your script element is actually part of the result tree, and so not accessible to xsl:value-of.
However, it is possible to extend XSLT so it can use javascript functions, but this is very much processor dependant, and you should think of it the same way as embedding JavaScript in HTML. Have a look at this question, as an example
How to include javaScript file in xslt
So, in your case, your XSLT would be something like this (Note this particular example will only work in Mircorsofts MSXML processor)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace"
exclude-result-prefixes="msxsl user">
<xsl:output method="xml" indent="yes" />
<msxsl:script language="JScript" implements-prefix="user">
var List={
"t1":"test"
}
function lookup(key) {
return List[key];
}
</msxsl:script>
<xsl:template match="root">
<html>
<div>
<xsl:variable name="name1" select="te"/>
<xsl:value-of select="user:lookup(string($name1))"/>
</div>
</html>
</xsl:template>
</xsl:stylesheet>
Of course, it might be worth asking why you want to use javascript in your XSLT. It may be possible to achieve the same result using purely XSLT, which would certainly make you XSLT more portable.