Get XML atribute using XSLT for a href on HTML - 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.

Related

Make a XSLT transformation in <iframe> without src

I want to embbed a XSLT transformation into an <iframe>. Here are my 2 files:
simple.html:
<!DOCTYPE html>
<html>
<body>
<iframe>
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="simple.xsl"?>
<text>
Hello World
</text>
</iframe>
</body>
</html>
simple.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
Content: <xsl:value-of select="." />
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Obviously, it doesn't work.
If I put the XML code of the <iframe> into a file named simple.xml and reference it like that <iframe src="simple.xml">, it works well but I don't want to have a separate XML file.
The reason is because the XML code will be provided by the user and I don't want to store it temporarily on my server just so I can reference it in the <iframe>, I want to do all client-side.
Is it possible to do that? If so, how can I do?
Thank you for your help.

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>

XSLT: Transforming into non-xml content?

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.

XSLT parse escaped HTML stored in an attribute and convert that attribute's content into element's content

I'm stuck on what I think should be simple thing to do. I've been looking around, but didn't find the solution. Hope you will help me.
What I have is an XML element with an attribute that contains escaped HTML elements:
<Booking>
<BookingComments Type="RAM" comment="RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com" />
</Booking>
What I need to get is parsed HTML elements and content from the #comment attribute to be a content of element as follows:
<p>
RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com
<p>
Here is my XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="xs fn" version="1.0">
<xsl:output method="html" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"
doctype-system="http://www.w3.org/TR/html4/loose.dtd" encoding="UTF-8" indent="yes" />
<xsl:template name="some-template">
<p>Some text</p>
<p>
<xsl:copy-of
select="/Booking/BookingComments[lower-case(#Type)='ram'][1]/#comment"/>
</p>
</xsl:template>
</xsl:stylesheet>
I've read that copy-of is a good way to restore escaped HTML elements back to proper elements. In this specific case, because it's initially an attribute the copy-of translates it into attribute as well. So I get:
<p comment="RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com"></p>
Which isn't what I want.
If I use apply-templates instead of copy-of, as in:
<p>
<xsl:apply-templates select="/Booking/BookingComments[lower-case(#Type)='ram'[1]/#comment"/>
</p>
I get p's content simply as text, not restored HTML elements.
<p>RAM name fred<br/>Tel 09876554<br/>Email fred#bla.com</p>
I'm sure I'm missing something obvous. I would really appreciate any help and tips!
I would recommend using a dedicated template:
<!-- check if lower-casing #Type is really necessary -->
<xsl:template name="BookingComments[lower-case(#Type)='ram']/#comment">
<p>
<xsl:value-of select="." disable-output-escaping="yes" />
</p>
</xsl:template>
This way you could simply apply templates to the attribute. Note that disabling output escaping has the potential to generate ill-formed output.
You could bind an extension function parse() which parses a string into a nodeset. The exact mechanism will depend on your XSLT engine.
In Xalan, we can take the following static method:
public class MyExtension
{
public static NodeIterator Parse( string xml );
}
and use it like so:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://xml.apache.org/xalan/java"
exclude-result-prefixes="java"
version="1.0">
<xsl:template match="BookingComments">
<xsl:copy-of select="java:package.name.MyExtension.Parse(string(#comment))" />
</xsl:template>
</xsl:stylesheet>