I am an amateur and have started XML and XSLT recently.
I've been asked to make a XSLT file from the below XML.
<?xml version="1.0" encoding="UTF-8" ?>
<event>
<title>Test 1</title>
<description>The first test</description>
<location>
<postalcode>A1A 1A1</postalcode>
<city>Vancouver</city>
<province>BC</province>
<streetaddress>Arina street east</streetaddress>
</location>
<attendees>
<name>John</name>
<email>example#gmail.com</email>
<phone>778777777</phone>
</attendees>
</event>
I made this XSLT file
<?xml version="1.0" encoding="utf-8"?>
<!-- event.xsl -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head><title><xsl:value-of select="title"/></title></head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="event">
<h2><xsl:value-of select="title"/></h2>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="description">
<p><xsl:value-of select="description"/></p>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="location">
<p>
<xsl:value-of select="streetaddress"/>
<xsl:value-of select="city"/>
<xsl:value-of select="province"/>
<xsl:value-of select="postalcode"/>
</p>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="attendees">
<xsl:for-each select="event/attendees">
<p>
<xsl:value-of select="name"/>
<xsl:value-of select="email"/>
<xsl:value-of select="phone"/>
</p>
</xsl:for-each>
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
this is the generated HTML
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-16">
<title></title></head>
<body>
<h2>Test 1</h2>
Test 1
<p></p>The first test
<p>Arina street eastVancouverBCA1A 1A1</p>
A1A 1A1
Vancouver
BC
Arina street east
John
example#gmail.com
778777777
</body>
</html>
this the desired html that I am looking for
<html>
<head>
<title>Test 1</title>
<body>
<h2>Test 1</h2>
<p>The first test</p>
<p>
Ariana Street East<br>
Vancouver<br>
BC , A1A 1A1<br>
</p>
<!-- repeat-->
<p>
Name:john<br>
Email:example#gmail.com<br>
Phone:77877777
</p>
<p>
Name:john2<br>
Email:example2#gmail.com<br>
Phone:77877778
</p>
</body>
</html>
when I make a HTML file it is kind of messed up.
would you let me know where are my mistakes?
do you have any easy explained article?
thank you
You may try this slightly adapted version:
<?xml version="1.0" encoding="utf-8"?>
<!-- event.xsl -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head>
<title>
<xsl:value-of select="event/title"/>
</title>
</head>
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="title" />
<xsl:template match="event">
<h2>
<xsl:value-of select="title"/>
</h2>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="description">
<p>
<xsl:value-of select="description"/>
</p>
</xsl:template>
<xsl:template match="location">
<p>
<xsl:value-of select="streetaddress"/>
<br/>
<xsl:value-of select="city"/>
<br/>
<xsl:value-of select="province"/>
<br/>
<xsl:value-of select="postalcode"/>
<br/>
</p>
</xsl:template>
<xsl:template match="attendees">
<p>
Name: <xsl:value-of select="name"/><br/>
Email: <xsl:value-of select="email"/><br/>
Phone: <xsl:value-of select="phone"/><br/>
</p>
</xsl:template>
</xsl:stylesheet>
Which will generate the following output:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test 1</title>
</head>
<body>
<h2>Test 1</h2>
<p></p>
<p>Arina street east<br>Vancouver<br>BC<br>A1A 1A1<br></p>
<p>
Name: John<br>
Email: example#gmail.com<br>
Phone: 778777777<br></p>
</body>
</html>
I think you have an error in "attendess" pattern match:
<xsl:template match="attendees">
<xsl:for-each select="event/attendees">
<p>...
The "for-each" instruction is redundant, attendees template is applied from de "apply-templates" instruction in the event template.
The first title section wont work, update it to:
<title><xsl:value-of select="event/title"/></title>
add field names at the begining and elements at the end of the lines on attendees and location
<xsl:template match="location">
<p>
address:<xsl:value-of select="streetaddress"/><br>
city:<xsl:value-of select="city"/><br>
province:<xsl:value-of select="province"/><br>
postalcode:<xsl:value-of select="postalcode"/> <br>
</p>
<xsl:apply-templates />
</xsl:template>
Related
I'm trying to write a simple XHTML to Simple Docbook translator (the input XHTML is a limited subset so it should be doable).
I have 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" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" standalone="no"/>
<!--
<xsl:strip-space elements="*"/>
-->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<!-- skip implicit tags-->
<xsl:template match="/html/body"><xsl:apply-templates/></xsl:template>
<xsl:template match="/html"><xsl:apply-templates/></xsl:template>
<!-- paragraphs to sections converter -->
<xsl:template match="h2">
<xsl:variable name="title" select="generate-id(.)"/>
<section>
<title><xsl:apply-templates select="text()"/></title>
<xsl:for-each select="following-sibling::*[generate-id(preceding-sibling::h2[1]) = $title and not(self::h2)]">
<xsl:apply-templates/>
</xsl:for-each>
</section>
</xsl:template>
<xsl:template match="p">
<para><xsl:apply-templates select="*|text()"/></para>
</xsl:template>
<xsl:template match="p[preceding-sibling::h2]"/>
<xsl:template match="ul">
<itemizedlist><xsl:apply-templates select="li"/></itemizedlist>
</xsl:template>
<xsl:template match="ul[preceding-sibling::h2]"/>
<xsl:template match="ol">
<orderedlist><xsl:apply-templates select="li"/></orderedlist>
</xsl:template>
<xsl:template match="ol[preceding-sibling::h2]"/>
<xsl:template match="li">
<listitem><para><xsl:apply-templates select="*|text()"/></para></listitem>
</xsl:template>
</xsl:stylesheet>
For this input
<html>
<body>
<p>First paragraph</p>
<p>Second paragraph</p>
<h2>First title</h2>
<p>First paragraph</p>
<p>Second paragraph</p>
<p>Third paragraph</p>
<h2>Second title</h2>
<p>First paragraph</p>
<ul>
<li>A list item</li>
<li>Another list item</li>
</ul>
<p>Second paragraph</p>
</body>
</html>
I expect this output
<para>First paragraph</para>
<para>Second paragraph</para>
<section>
<title>First title</title>
<para>First paragraph</para>
<para>Second paragraph</para>
<para>Third paragraph</para>
</section>
<section>
<title>Second title</title>
<para>First paragraph</para>
<itemizedlist>
<listitem>A list item</listitem>
<listitem>Another list item</listitem>
</itemizedlist>
<para>Second paragraph</para>
</section>
But I get
<para>First paragraph</para>
<para>Second paragraph</para>
<section><title>First title</title>First paragraphSecond paragraphThird paragraph</section>
<section><title>Second title</title>First paragraph
<listitem><para>A list item</para></listitem>
<listitem><para>Another list item</para></listitem>
Second paragraph</section>
For some reason, the template for my paragraphs and lists is not being applied. I'm guessing because the templates matching are the empty ones, but I need those to prevent duplicate tags outside section.
How can I make this work? TIA.
Use
<xsl:for-each select="following-sibling::*[generate-id(preceding-sibling::h2[1]) = $title and not(self::h2)]">
<xsl:apply-templates select="."/>
</xsl:for-each>
or simply
<xsl:apply-templates select="following-sibling::*[generate-id(preceding-sibling::h2[1]) = $title and not(self::h2)]"/>
to process those elements you want to wrap into a section. But there will be a collision with your other templates so perhaps using a mode helps for the processing:
<xsl:template match="p" mode="wrapped">
<para><xsl:apply-templates select="*|text()"/></para>
</xsl:template>
<xsl:template match="p[preceding-sibling::h2]"/>
<xsl:template match="ul" mode="wrapped">
<itemizedlist><xsl:apply-templates select="li"/></itemizedlist>
</xsl:template>
<xsl:template match="ul[preceding-sibling::h2]"/>
<xsl:template match="ol" mode="wrapped">
<orderedlist><xsl:apply-templates select="li"/></orderedlist>
</xsl:template>
<xsl:template match="ol[preceding-sibling::h2]"/>
<xsl:template match="li" mode="wrapped">
<listitem><para><xsl:apply-templates select="*|text()"/></para></listitem>
</xsl:template>
I have xml code:
<presentation>
<slide type="title-slide" poradie="1">
<title>Here is title.</title>
<autor>Name of autor.</autor>
</slide>
</presentation>
And here is my xslt:
<xsl:template match="/presentation/slide">
<xsl:variable name="filename" select="concat('output_new/',#poradie,'.xhtml')"/>
<xsl:value-of select="$filename" />
<xsl:result-document href="{$filename}" format="xhtml">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
&css;
</style>
</head>
<body>
<div class="slide">
<xsl:apply-templates/>
</div>
</body>
</html>
</xsl:result-document>
</xsl:template>
<xsl:template match="slide[#type = 'title-slide']">
<div class="container_title_slide">
<h1><xsl:value-of select="title"/></h1>
<h3><xsl:value-of select="autor"/></h3>
</div>
</xsl:template>
So I want to create XHTML file for each slide. I need to match slide tag two times. Can you help me?
At the moment, both your templates match with the same priority, which is considered an error
What you can do is firstly give the first template a higher-priority
<xsl:template match="/presentation/slide" priority="2">
Then, in your template body, use <xsl:next-match /> instead of <xsl:apply-templates/> which would then apply the template with the lower priorty (Note that <xsl:apply-templates/> would be looking for templates that match child nodes, so was not right to use in this case anyway).
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml" version="2.0">
<xsl:output method="html" indent="yes" />
<xsl:template match="/presentation/slide" priority="2">
<xsl:variable name="filename" select="concat('output_new/',#poradie,'.xhtml')"/>
<xsl:value-of select="$filename" />
<xsl:result-document href="{$filename}" format="xhtml">
<html>
<head>
<style>
&css;
</style>
</head>
<body>
<div class="slide">
<xsl:next-match />
</div>
</body>
</html>
</xsl:result-document>
</xsl:template>
<xsl:template match="slide[#type = 'title-slide']">
<div class="container_title_slide">
<h1><xsl:value-of select="title"/></h1>
<h3><xsl:value-of select="autor"/></h3>
</div>
</xsl:template>
</xsl:stylesheet>
(Note that I replace &css; with &css; as &css; is not a valid XML entity).
How can I apply a different font in an XSL for the XML looking like this
<text> sometext <citation> somecitation </citation> sometext </text>
so the citation content should be in a different font as just text.
so this is the part of my XML
<text>She flipped her bed over and found invisible alligators all over her room. <citation> What's going on here? <citation> she demanded. </text>
I wrote a code <xsl:template match="text">
<p>
<xsl:value-of select="text()"/>
<q>
<xsl:value-of select="citation/text()"/>
</q>
</p>
(q stands for italic in CSS)
What I want to get :
She flipped her bed over and found invisible alligators all over her room.
"What's going on here?" she demanded.
What I get for now : She flipped her bed over and found invisible alligators all over her room.she demanded. "What's going on here?"
how can I proceed to get correct result?
Thank you!
First, the default styling applied by the browser should be quite sufficient - provided you use the correct HTML tags.
Given the following input:
XML
<text>She flipped her bed over and found invisible alligators all over her room. <citation> What's going on here? </citation> she demanded. </text>
the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="text">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="citation">
<cite>
<xsl:apply-templates/>
</cite>
</xsl:template>
</xsl:stylesheet>
will return:
<html>
<body>
<p>She flipped her bed over and found invisible alligators all over her room. <cite> What's going on here? </cite> she demanded.
</p>
</body>
</html>
which most any browser will render as:
If you don't like or don't trust the browser defaults, you can specify your own style, for example:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="text">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="citation">
<span style="font-style: italic;">
<xsl:apply-templates/>
</span>
</xsl:template>
</xsl:stylesheet>
Or:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<head>
<style>
q {
font-style: italic;;
}
</style>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="text">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="citation">
<q>
<xsl:apply-templates/>
</q>
</xsl:template>
</xsl:stylesheet>
I have a project where I need a to convert an xml to html using an XSLT and have a css for it as well. I just can't seem to get the CSS to affect the document, any help would be great!
The CSS is just align center because I can easily see if it's working or not, once I know it's working I can edit it so it's how i want it to be. But basically the XSL works fine but I can't get the CSS to affect the xml
XML:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="BookDescription.xsl" type="text/xsl"?>
<?xml-stylesheet type="text/css" href="book_details.css"?>
<!--ORACLE BOOK-->
<Book>
<bookID>0-07-882122-3</bookID>
<bookTitle>Oracle: A Beginner's Guide</bookTitle>
<bookCategory>database</bookCategory>
<bookDescription>A beginner's guide to the complex and powerful Oracle database management system. Teaches you how to set up, query and manage your database, including principles of database design, how to manage data, generate reports and tune the system for optimal performance.</bookDescription>
<bookPrice>30.00</bookPrice>
<bookAuthor>Michael Abbey</bookAuthor>
<bookImage>images/Oracle.JPG</bookImage>
<bookInfo>Oracle.xml</bookInfo>
</Book>
XSL
<?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" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="Book">
<h3>
<xsl:value-of select="bookTitle"/>
</h3>
<img alt="">
<xsl:attribute name="src"><xsl:value-of select="bookImage"/></xsl:attribute>
</img>
<div>
<xsl:text>ISBN: </xsl:text>
<xsl:value-of select="bookID"/>
</div>
<div>
<xsl:text>Author: </xsl:text>
<xsl:value-of select="bookAuthor"/>
</div>
<div>
<xsl:text>Category: </xsl:text>
<xsl:value-of select="bookCategory"/>
</div>
<div>
<xsl:text>Description: </xsl:text>
<xsl:value-of select="bookDescription"/>
</div>
<div>
<xsl:text>Price: </xsl:text>
<xsl:value-of select="bookPrice"/>
</div>
</xsl:template>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="Book"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
CSS
div{
text-align: center;
}
bookID{
text-align: center;
}
You have to add a link to your CSS file:
<xsl:template match="/">
<html>
<head>
<link rel="stylesheet" href="path/to/your/css/file.css">
</head>
<body>
<xsl:apply-templates select="Book"/>
</body>
</html>
</xsl:template>
Or:
<xsl:template match="/">
<html>
<head>
<style>
/* Your CSS here */
</style>
</head>
<body>
<xsl:apply-templates select="Book"/>
</body>
</html>
</xsl:template>
So I have a XML document generated by my application like this:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE AddressBook>
<?xml-stylesheet type="text/xsl" href="stylesheet.xsl"?>
<AddressBook>
<Item>
<UserGeneratedElementName1 class="info">Whatever blah blah</UserGeneratedElementName1>
<UserGeneratedElementName2 class="info">Whatever blah blah</UserGeneratedElementName2>
</Item>
<Item>
<UserGeneratedElementName3 class="info">Whatever blah blah</UserGeneratedElementName3>
</Item>
...
...
Other Items with user-generated elements with user-generated content...
</AddressBook>
And I want to turn it into a HTML document similar to this:
<html>
<head>
<title>AddressBook</title>
</head>
<body>
<div class="root">
<div class="item">
<b>UserGeneratedElementName1:</b> Whatever blah blah
<b>UserGeneratedElementName2:</b> Whatever blah blah
</div>
<div class="item">
<b>UserGeneratedElementName3:</b> Whatever blah blah
</div>
...
...
Other transformed items...
</div>
</body>
</html>
I have tried to get a grasp of the XSLT syntax, but all the guides were either too vague to help me with this or too deep. Also XSLT syntax seems quite confusing.
Thanks in advance.
Take a look at this question here
Is there an XSLT name-of element?
You can use
<xsl:value-of select ="name(.)"/>
or
<xsl:value-of select ="local-name()"/>
to get the name of a node, depending on if you want to include the full prefixed name, or just the local portion.
You should be able to piece those together with xsl:for-each blocks to iterate through the first 3 levels of items and generate the HTML you're looking for.
Something like this would work for a fixed number of levels.
<xsl:for-each select="*">
<html>
<head>
<title><xsl:value-of select="local-name()" /></title>
</head>
<body>
<div class="root">
<xsl:for-each select="*">
<div>
<xsl:attribute name="class">
<xsl:value-of select="local-name()" />
</xsl:attribute>
<xsl:for-each select="*">
<b><xsl:value-of select="local-name()" />:</b> <xsl:value-of select="." />
</xsl:for-each>
</div>
</xsl:for-each>
</div>
</body>
</html>
</xsl:for-each>
A more generic approach would look something more like:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes" version="4.0"/>
<xsl:template match="/">
<xsl:for-each select="*">
<html>
<head>
<title><xsl:value-of select="local-name()" /></title>
</head>
<body>
<div class="root">
<xsl:call-template name="recurseElement">
<xsl:with-param name="element" select="." />
</xsl:call-template>
</div>
</body>
</html>
</xsl:for-each>
</xsl:template>
<xsl:template name="recurseElement">
<xsl:param name="element" />
<xsl:for-each select="$element/*">
<xsl:choose>
<xsl:when test="count(child::*)>0">
<div>
<xsl:attribute name="class">
<xsl:value-of select="local-name()" />
</xsl:attribute>
<xsl:call-template name="recurseElement">
<xsl:with-param name="element" select="." />
</xsl:call-template>
</div>
</xsl:when>
<xsl:otherwise>
<b><xsl:value-of select="local-name()" />:</b> <xsl:value-of select="." />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
This complete XSLT transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="AddressBook">
<html>
<head>
<title>AddressBook</title>
</head>
<body>
<div class="root">
<xsl:apply-templates/>
</div>
</body>
</html>
</xsl:template>
<xsl:template match="Item">
<div class="item"><xsl:apply-templates/></div>
</xsl:template>
<xsl:template match="Item/*">
<b><xsl:value-of select="name()"/>:</b> <xsl:text/>
<xsl:value-of select="concat(.,'
')"/>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<AddressBook>
<Item>
<UserGeneratedElementName1 class="info">Whatever blah blah</UserGeneratedElementName1>
<UserGeneratedElementName2 class="info">Whatever blah blah</UserGeneratedElementName2>
</Item>
<Item>
<UserGeneratedElementName3 class="info">Whatever blah blah</UserGeneratedElementName3>
</Item> ... ... Other Items with user-generated elements with user-generated content...
</AddressBook>
produces the wanted, correct result:
<html>
<head>
<title>AddressBook</title>
</head>
<body>
<div class="root">
<div class="item">
<b>UserGeneratedElementName1:</b>Whatever blah blah
<b>UserGeneratedElementName2:</b>Whatever blah blah
</div>
<div class="item">
<b>UserGeneratedElementName3:</b>Whatever blah blah
</div> ... ... Other Items with user-generated elements with user-generated content...
</div>
</body>
</html>
Explanation:
Templates matching any Item element and any element child of an Item element.
Use of the standard XPath name() function.