I have an xml file like this
<generic-cv:generic-cv xmlns:generic-cv="http://www.cihr-irsc.gc.ca/generic-cv/1.0.0" lang="en" dateTimeGenerated="2014-05-30 11:40:50">
<section id="f589cbc028c64fdaa783da01647e5e3c" label="Personal Information">
<section id="2687e70e5d45487c93a8a02626543f64" label="Identification" recordId="4f7c2ebd789f407b939e05664f6aa7c0">
<field id="ee8beaea41f049d8bcfadfbfa89ac09e" label="Title">
<lov id="00000000000000000000000000000318">Mr.</lov>
</field>
<field id="5c6f17e8a67241e19667815a9e95d9d0" label="Family Name">
<value type="String">ali</value>
</field>
<field id="98ad36fee26a4d6b8953ea764f4fed04" label="First Name">
<value type="String">Hara</value>
</field>
</section>
<section id="2687e70e5d45487c93a8a02626543f64" label="Identification" recordId="4f7c2ebd789f407b939e05664f6aa7c0">
<field id="ee8beaea41f049d8bcfadfbfa89ac09e" label="Title">
<lov id="00000000000000000000000000000318">Mr.</lov>
</field>
<field id="5c6f17e8a67241e19667815a9e95d9d0" label="Family Name">
<value type="String">fara</value>
</field>
<field id="98ad36fee26a4d6b8953ea764f4fed04" label="First Name">
<value type="String">hhh</value>
</field>
</section>
</section>
</generic-cv:generic-cv>
and an xslt file like this
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Xml Convertor</title>
</head>
<body>
<h2><b> Personal Information</b></h2>
<xsl:for-each select=".//section[#id='2687e70e5d45487c93a8a02626543f64']" />
<ul>
<li>Name: <xsl:value-of select=".//field[#id='98ad36fee26a4d6b8953ea764f4fed04']/value" />, <xsl:value-of select=".//field[#id='5c6f17e8a67241e19667815a9e95d9d0']/value" /></li>
</ul>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I want loop through each section with a certain id number and print out the names in a list. Should look something like this
Hara
hhh
What i have tried so far is not working. Would someone be able to take a look and see what I did wrong
Here is the correct XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Xml Convertor</title>
</head>
<body>
<h2><b> Personal Information</b></h2>
<ul>
<xsl:for-each select=".//section[#id='2687e70e5d45487c93a8a02626543f64']" >
<li>Name: <xsl:value-of select=".//field[#id='98ad36fee26a4d6b8953ea764f4fed04']/value" />, <xsl:value-of select=".//field[#id='5c6f17e8a67241e19667815a9e95d9d0']/value" /></li>
</xsl:for-each>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I have check it with XSLT Tryit Editor from w3schools and this produces:
Personal Information
Name: Hara, ali
Name: hhh, fara
In your for-each loop you need to select the First Name and Family Name fields, instead of ids, as shown below:
<xsl:for-each select=".//section[#id='2687e70e5d45487c93a8a02626543f64']" >
<li><xsl:value-of select="field[#label='First Name']/value" />,<xsl:value-of select="field[#label='Family Name']/value" /></li>
</xsl:for-each>
Related
I have an xml file, that describes a conversation between Agent and Client. Both parties have a userId, that is assigned in the newParty tag.
Subsequent messages and notices, refer to this userId. I would like for when a message or a notice is processed, that a lookup is done by using the userId, to add the string "Agent" or "Client" to the class property of the generated HTML.
<?xml version="1.0"?>
<chatTranscript startAt="2016-10-06T09:16:40Z" sessionId="0001GaBYC53D000K">
<newParty userId="007957F616780001" timeShift="1" visibility="ALL" eventId="1">
<userInfo personId="" userNick="John Doe" userType="CLIENT" protocolType="FLEX" timeZoneOffset="120"/>
<userData>
<item key="GMSServiceId">5954d184-f89d-4f44-8c0f-a772d458b353</item>
<item key="IdentifyCreateContact">3</item>
<item key="MediaType">chat</item><item key="TimeZone">120</item>
<item key="_data_id">139-e9826bf5-c5a4-40e5-a729-2cbdb4776a43</item>
<item key="firstName">John</item><item key="first_name">John</item>
<item key="lastName">Doe</item>
<item key="last_name">Doe</item>
<item key="location_lat">37.8197</item>
<item key="location_long">-122.4786</item>
<item key="userDisplayName">John Doe</item>
</userData>
</newParty>
<newParty userId="0079581AF56C0025" timeShift="20" visibility="ALL" eventId="2">
<userInfo personId="1" userNick="allendei" userType="AGENT" protocolType="BASIC" timeZoneOffset="120"/>
</newParty>
<message userId="007957F616780001" timeShift="25" visibility="ALL" eventId="3">
<msgText msgType="text" treatAs="NORMAL">This is message one.</msgText>
</message>
<message userId="0079581AF56C0025" timeShift="35" visibility="ALL" eventId="4">
<msgText msgType="text" treatAs="NORMAL">This is message two.</msgText>
</message>
<notice userId="0079581AF56C0025" timeShift="40" visibility="ALL" eventId="5">
<noticeText noticeType="USER_CUSTOM">This is notice one.</noticeText>
</notice>
<notice userId="007957F616780001" timeShift="58" visibility="ALL" eventId="6">
<noticeText noticeType="USER_CUSTOM">This is notice two.</noticeText>
</notice>
<partyLeft userId="007957F616780001" timeShift="90" visibility="ALL" eventId="4" askerId="007957F616780001">
<reason code="3">left due to disconnect</reason>
</partyLeft>
... and my xlt is:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:template match="/chatTranscript">
<html>
<header><xsl:value-of select="#sessionId" /></header>
<xsl:apply-templates select="newParty" />
<xsl:apply-templates select="message/msgText" />
<xsl:apply-templates select="notice/noticeText" />
<xsl:apply-templates select="partyLeft/reason" />
</html>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='CLIENT']">
<div class="Client" id="{#userId}">
<label>Client: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='AGENT']">
<div class="Client" id="{#userId}">
<label>Agent: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="msgText">
<div class="Messages" id="{../#eventId}">
<label>Message: <xsl:value-of select="text()" /></label>
</div>
</xsl:template>
<xsl:template match="noticeText">
<div class="Notices" id="{../#eventId}">
<label>Notice: <xsl:value-of select="text()" /></label>
</div>
</xsl:template>
<xsl:template match="reason">
<div class="Notices" id="{../#eventId}">
<label>Reason: <xsl:value-of select="text()" /></label>
</div>
</xsl:template>
the desired output is as follows - where the class property(Agent or Client) of Messages and Notices are lookup up via the userID in the newParties at the top.
<html>
<header>0001GaBYC53D000K</header>
<div class="Client" id="007957F616780001"><label>Client: John Doe</label></div>
<div class="Client" id="0079581AF56C0025"><label>Agent: allendei</label></div>
<div class="Messages,Client" id="3"><label>Message: This is message one.</label></div>
<div class="Messages,Agent" id="4"><label>Message: This is message two.</label></div>
<div class="Notices,Agent" id="5"><label>Notice: This is notice one.</label></div>
<div class="Notices,Client" id="6"><label>Notice: This is notice two.</label></div>
<div class="Notices,Client" id="4"><label>Reason: left due to disconnect</label></div>
XSLT has a built-in mechanism for performing lookups. Start by defining a key as:
<xsl:key name="party" match="newParty" use="#userId" />
then use it as shown in the following example:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:key name="party" match="newParty" use="#userId" />
<xsl:template match="/chatTranscript">
<html>
<header>
<xsl:value-of select="#sessionId" />
</header>
<xsl:apply-templates/>
</html>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='CLIENT']">
<div class="Client" id="{#userId}">
<label>Client: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="newParty[userInfo/#userType='AGENT']">
<div class="Client" id="{#userId}">
<label>Agent: <xsl:value-of select="userInfo/#userNick" /></label>
</div>
</xsl:template>
<xsl:template match="message">
<xsl:variable name="party-class">
<xsl:call-template name="lookup-class"/>
</xsl:variable>
<div class="Messages,{$party-class}" id="{#eventId}">
<label>Message: <xsl:value-of select="msgText" /></label>
</div>
</xsl:template>
<xsl:template match="notice">
<xsl:variable name="party-class">
<xsl:call-template name="lookup-class"/>
</xsl:variable>
<div class="Notices,{$party-class}" id="{#eventId}">
<label>Notice: <xsl:value-of select="noticeText" /></label>
</div>
</xsl:template>
<xsl:template match="partyLeft">
<xsl:variable name="party-class">
<xsl:call-template name="lookup-class"/>
</xsl:variable>
<div class="Notices,{$party-class}" id="{#eventId}">
<label>Reason: <xsl:value-of select="reason" /></label>
</div>
</xsl:template>
<xsl:template name="lookup-class">
<xsl:variable name="party-type" select="key('party', #userId)/userInfo/#userType" />
<xsl:choose>
<xsl:when test="$party-type='CLIENT'">Client</xsl:when>
<xsl:when test="$party-type='AGENT'">Agent</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Note that the output is not valid HTML.
I am trying to produce a HTML table from some XML I have got through a SQL query. The XML produced looks like the following:
<root>
<form attribute1="1" attribute2="1" />
<form attribute1="1" attribute2="2" />
<form attribute1="1" attribute2="3" />
<form attribute1="2" attribute2="1" />
<form attribute1="2" attribute2="2" />
<form attribute1="3" attribute2="1" />
</root>
The table I am trying to produce needs to have a header row for each unique attribute1 with rows underneath for each attribute2, something like this:
<attribute1="1" />
<attribute2="1" />
<attribute2="2" />
<attribute2="3" />
<attribute1="2" />
<attribute2="1" />
<attribute2="2" />
<attribute1="3" />
<attribute2="1" />
I don't have much experience using XML/XSLT but I am hoping it would be possible to do something like loop through the forms, create a header row for each unique attribute1 then create data rows associated to the unique attribute1 underneath.
If you can only use XSLT 1.0, try this XSLT for starters, which uses the Muenchian Grouping method
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="form" match="form" use="#attribute1" />
<xsl:template match="root">
<xsl:copy>
<!-- Get first "form" element that occurs in each group -->
<xsl:for-each select="form[generate-id() = generate-id(key('form',#attribute1)[1])]">
<group>
<header><xsl:value-of select="#attribute1" /></header>
<!-- Get the "form" elements that make up the group -->
<xsl:apply-templates select="key('form', #attribute1)" />
</group>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="form">
<row><xsl:value-of select="#attribute2" /></row>
</xsl:template>
</xsl:stylesheet>
And here's some XSLT that can create an HTML table. This one is slightly more advanced as it works out the maximum number of columns for a row, and uses that in creating colspan attributes for the shorter rows
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:key name="form" match="form" use="#attribute1" />
<xsl:variable name="maxCells">
<xsl:for-each select="/root/form[generate-id() = generate-id(key('form',#attribute1)[1])]">
<xsl:sort select="count(key('form', #attribute1))" order="descending" />
<xsl:if test="position() = 1">
<xsl:value-of select="count(key('form', #attribute1))" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="root">
<table border="1">
<!-- Get first "form" element that occurs in each group -->
<xsl:for-each select="form[generate-id() = generate-id(key('form',#attribute1)[1])]">
<tr>
<th colspan="{$maxCells}">
<xsl:value-of select="#attribute1" />
</th>
</tr>
<tr>
<!-- Get the "form" elements that make up the group -->
<xsl:apply-templates select="key('form', #attribute1)" />
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="form">
<td>
<xsl:if test="position() = last()">
<xsl:attribute name="colspan">
<xsl:value-of select="$maxCells - count(key('form', #attribute1)) + 1" />
</xsl:attribute>
</xsl:if>
<xsl:value-of select="#attribute2" />
</td>
</xsl:template>
</xsl:stylesheet>
I am new to using XSLT and I am struggling with a problem . I want to print out the text between the xml tags.
XML code
<?xml version="1.0" encoding="UTF-8"?>
<generic-cv:generic-cv xmlns:generic-cv="http://www.cihr-irsc.gc.ca/generic-cv/1.0.0" lang="en" dateTimeGenerated="2014-05-30 11:40:50">
<section id="f589cbc028c64fdaa783da01647e5e3c" label="Personal Information">
<section id="2687e70e5d45487c93a8a02626543f64" label="Identification" recordId="4f7c2ebd789f407b939e05664f6aa7c0">
<field id="ee8beaea41f049d8bcfadfbfa89ac09e" label="Title">
<lov id="00000000000000000000000000000318">Mr.</lov>
</field>
<field id="5c6f17e8a67241e19667815a9e95d9d0" label="Family Name">
<value type="String">ali</value>
</field>
<field id="98ad36fee26a4d6b8953ea764f4fed04" label="First Name">
<value type="String">Hara</value>
</field>
<field id="4ca83c1aaa6a42a78eac0290368e70f3" label="Middle Name">
<value type="String"/>
</field>
<field id="41ed5ea3ae974428b3fcb592161b6423" label="Date of Birth">
<value format="MM/dd" type="MonthDay">8/23</value>
</field>
<field id="2b72a344523c467da0c896656b5290c0" label="Correspondence language">
<lov id="00000000000000000000000000000054">English</lov>
</field>
</section>
</section>
xslt code
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Xml Convertor</title>
</head>
<body>
<h2><b> Personal Information</b></h2>
<ul>
<li>Name:</li>
<li> Date of Birth:</li>
<li> Language:</li>
</ul>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
what i have tried using so far is
<xsl:value-of select="concat('<',name(parent::*),'> ',.,'
')"/>
but this will print out all the info between the tags
I would like the the output to be like
Name: Hara ali
Date of Birth: 8/23
Language: English
How can I do this with xslt?
Thank you!
The text from a node can be received by using xsl:value-of, you will want to select the fields by their label, something like:
<xsl:value-of select=".//field[#label='First Name']/value" />
You should be able to get the rest by yourself.
How to convert all LF chars to <br /> tags and show it on the HTML page?
I have the following example XML file:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="data.xslt"?>
<data>
<lines>
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
</lines>
</data>
and I want to show all lines on the HTML page. For this I use the following XSLT transformation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<xsl:variable name="filtered">
<xsl:call-template name="replace">
<xsl:with-param name="string" select="./data/lines"/>
<xsl:with-param name="search" select="'
'"/>
<xsl:with-param name="new"><br /></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<td align="left">
<xsl:value-of select="$filtered" disable-output-escaping="yes"/>
</td>
</body>
</html>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="string"/>
<xsl:param name="search"/>
<xsl:param name="new"/>
<xsl:choose>
<xsl:when test="contains($string, $search)">
<xsl:value-of select="substring-before($string, $search)"/>
<xsl:value-of select="$new"/>
<xsl:call-template name="replace">
<xsl:with-param name="string" select="substring-after($string, $search)"/>
<xsl:with-param name="search" select="$search"/>
<xsl:with-param name="new" select="$new"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When I open that XML file in Firefox (I use browser to show XSLT transformation) I will see that result:
Line 1Line 2Line 3Line 4Line 5Line 6
As you see, LF chars were not replaced by <br /> tags.
But when I use other string, for example EOL:
<xsl:with-param name="new">EOL</xsl:with-param>
I will see expected result:
EOLLine 1EOLLine 2EOLLine 3EOLLine 4EOLLine 5EOLLine 6EOL
The problem is with the convert/display <br /> tag.
You can pass a node fragment as a parameter value, as you do with <xsl:with-param name="new"><br /></xsl:with-param>, but to output that as a br element in your template you need to use <xsl:copy-of select="$new"/>, not xsl:value-of.
[edit] Here is an example: http://home.arcor.de/martin.honnen/xslt/test2012062801.xml. The stylesheet is at http://home.arcor.de/martin.honnen/xslt/test2012062801.xsl, I will also include it below:
<?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.01" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Example</title>
</head>
<body>
<xsl:variable name="filtered">
<xsl:call-template name="replace">
<xsl:with-param name="string" select="data/lines"/>
<xsl:with-param name="search" select="'
'"/>
<xsl:with-param name="new"><br /></xsl:with-param>
</xsl:call-template>
</xsl:variable>
<div>
<xsl:copy-of select="$filtered"/>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="replace">
<xsl:param name="string"/>
<xsl:param name="search"/>
<xsl:param name="new"/>
<xsl:choose>
<xsl:when test="contains($string, $search)">
<xsl:value-of select="substring-before($string, $search)"/>
<xsl:copy-of select="$new"/>
<xsl:call-template name="replace">
<xsl:with-param name="string" select="substring-after($string, $search)"/>
<xsl:with-param name="search" select="$search"/>
<xsl:with-param name="new" select="$new"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
You have extra quotes in your parameter value. Try changing the line...
<xsl:with-param name="search" select="'
'"/>
To...
<xsl:with-param name="search" select="
"/>
UPDATE
As pointed out by the OP, the above is incorrect and will cause an XSLT transformation error.
I believe the answer by #banana to be the correct one.
IMHO, xsl:anaylze-string is the perfect fit for this problem. This XSLT 2.0 style-sheet run under Saxon ...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:so="http://stackoverflow.com/questions/11222334"
xmlns:x="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/1999/xhtml"
exclude-result-prefixes="xsl fn xs so x">
<xsl:output method="xhtml" encoding="utf-8" indent="yes"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
omit-xml-declaration="yes" />
<xsl:template match="/">
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/></head>
<body>
<xsl:apply-templates select="data/lines"/>
</body>
</html>
</xsl:template>
<xsl:template match="lines">
<xsl:analyze-string select="." regex="\n">
<xsl:matching-substring>
<br />
<xsl:value-of select="'
'" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
... when applied to this input document ...
<?xml version="1.0" encoding="utf-8"?>
<data>
<lines>
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
</lines>
</data>
... will produce this html page ...
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body><br />
Line 1<br />
Line 2<br />
Line 3<br />
Line 4<br />
Line 5<br />
Line 6<br />
</body>
</html>
Try to replace:
<xsl:with-param name="new"><br /></xsl:with-param>
with:
<xsl:with-param name="new"><br /></xsl:with-param>
this will write current node value replacing \n with <br/>
<xsl:value-of select="replace(., '\n', '<br/>')"/>
I am working on a simple dictionary in XML, and now I'm trying to output some words vertical, but they all come out on a line without spaces.
This is some of the XML file
<thesaurus>
<dictionary>
<language>English</language>
<word type="1">word 1</word>
<word type="2">word 2</word>
<word type="3">word 3</word>
<word type="4">word 4</word>
<word type="5">word 5</word>
<word type="6">word 6</word>
</dictionary>
</thesaurus>
This is my first "almost" solution
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="//word">
<xsl:sort order="ascending"/>
</xsl:apply-templates>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
That solution only prints out all the word like this
AgentsColorFoundationsGrainPartialPogotypePretendSilentStrollTender
My second try is something like this
<xsl:for-each select="thesaurus">
<h1> <xsl:value-of select="//word"/></h1>
</xsl:for-each>
In that way I could style the words and they will print vertical, but the thing is that only the first of the words is printing. =/
Would be great with a hint :)
Thanks
Use this template:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="*/*/word">
<xsl:sort order="ascending"/>
</xsl:apply-templates>
</body>
</html>
</xsl:template>
<xsl:template match="word">
<xsl:value-of select="."/>
<br/>
</xsl:template>
</xsl:stylesheet>
Output:
<html>
<body>word 1<br />word 2<br />word 3<br />word 4<br />word 5<br />word 6<br /></body>
</html>