Working with an XSLT barchart - xslt

Hello so i've been making a bar chart. Which takes xml code and transforms it into a svg bar chart. I've made one with data going in the normal way, with the 'questions' running along the x-axis and data going up the y-axis. I want the bar chart to display questions going up the y-axis and then the data going along the x-axis. I'm not sure how to go about this.
<?xml version="1.0"?>
<?xml-stylesheet type='text/xsl' href='mytransformation.xslt'
?>
<Survey>
<Questions>
<Number>1</Number>
<Question>Is there free circulation of air through and about the building in which you work?</Question>
<Comment>"One says where she is employed there are 100 women and small girls who work in a cellar without ventilation, and gas and electric lights burning all day."</Comment>
<Yes>468</Yes>
<No>249</No>
<Blank>93</Blank>
</Questions>
<Questions>
<Number>2</Number>
<Question>Are there offensive odors in the rooms occupied by employees; if so, from what causes?</Question>
<Comment>"Eighty-one from water-closets and seventy-three from various other causes."</Comment>
<Yes>342</Yes>
<No>233</No>
<Blank>235</Blank>
</Questions>
<Questions>
<Number>3</Number>
<Question>Are there facilities for washing?</Question>
<Comment>Fourteen answered yes, but if caught washing are fined.</Comment>
<Yes>460</Yes>
<No>124</No>
<Blank>226</Blank>
</Questions>
<Questions>
<Number>4</Number>
<Question>Are seats provided, as prescribed by law?</Question>
<Yes>320</Yes>
<No>192</No>
<Blank>298</Blank>
</Questions>
</Survey>
This is the xslt code.
<?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>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="/">
<svg width="1000" height="1500">
<text id="title" x="500" y="50px" text-anchor="middle" style="fill:rgb(0,0,0);font-size:20;">SANITARY CONDITIONS OF WORKSHOPS AND FACTORIES</text>
<text id="50percentlabel" x="45" y="260" text-anchor="end">50%</text>
<text id="1000percentlabel" x="45" y="70" text-anchor="end">100%</text>
<text id="legendlabel" x="750" y="200">Legend: Survey Responses</text>
<rect height="20" width="50" x="750" y="220" fill="blue"/>
<text id="legend" x="810" y="235">Blank</text>
<rect height="20" width="50" x="750" y="250" fill="red"/>
<text id="legend" x="810" y="265">No</text>
<rect height="20" width="50" x="750" y="280" fill="black"/>
<text id="legend" x="810" y="295">Yes</text>
<line id="xaxis" x1="50" y1="450" x2="700" y2="450" style="stroke:rgb(0,0,0);"/>
<line id="yaxis" x1="50" y1="70" x2="50" y2="450" style="stroke:rgb(0,0,0);"/>
<xsl:for-each select="Survey/Questions">
<xsl:sort select="No" order="descending"/>
<xsl:if test="Yes">
<g>
<rect height="{(Blank div (Yes + No + Blank))*380}" width="25" x="{10+ (position()*50)}" y="70" fill="blue"/>
</g>
<g>
<rect height="{(No div (Yes + No + Blank))*380}" width="25" x="{10+ (position()*50)}" y="{70+(Blank div (Yes + No + Blank))*380}" fill="red"/>
</g>
<g>
<rect height="{(Yes div (Yes + No + Blank))*380}" width="25" x="{10+ (position()*50)}" y="{70+((Blank + No) div (Yes + No + Blank))*380}" fill="black"/>
</g>
<text id="Question" x="{15+ (position()*50)}" y="455" style="writing-mode: tb; glyph-orientation-vertical: 0;" >Q<xsl:number value="position()"/>: <xsl:value-of select="Question"/></text>
</xsl:if>
</xsl:for-each>
</svg>
</xsl:template>
</xsl:stylesheet>

Related

FOP XSL-FO Internal page anchor link URI problems

Morning folks!
So I am currently working on an FOP solution for a project, the end goal of which is basically to allow me to print onto a medium with the second iteration of the same information upside down, a feature which is not possible in Access 2007.
Everything is working swimmingly, and I can get the FOP to parse when I duplicate the code for the front side and use it for the back side.
However, when I try to use the parameter, I am getting an error I simply don't understand from the FOP terminal, having spent the better part of 4-5 hours trying to get my head around it. Code and error to follow.
<?xml version="1.0" encoding="utf-8"?>
<!-- WARNING - THIS TEMPLATE IS FOR Z FOLD CANON STOCK - DOUBLE SIDED -->
<!-- In order to covert CM to pixels, multiply the CM by 37.7952755905511, and round to two decimal places. It may be easier to use a spreadsheet to do this if you are editing multiple values -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<!-- EDIT THIS ROW TO CHANGE THE SIZE OF THE PAGE - AKA SET THIS TO THE SIZE OF THE MEDIUM YOU ARE PRINTING TO - CONVERTED TO PIXELS-->
<fo:simple-page-master master-name="simple" page-height="740.787px" page-width="317.480px">
<!-- IGNORE EVERYTHING BETWEEN HERE-->
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple">
<fo:flow flow-name="xsl-region-body">
<xsl:for-each select="//Person">
<fo:block>
<fo:instream-foreign-object>
<!--<svg xmlns="http://www.w3.org/2000/svg">-->
<!-- AND HERE-->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="370.4" height="634.96">
<g class="mirrorpage">
<rect style= "fill:none; stroke: black" width="370.394" height="317.480"/>
<text x="37.8" y="122.83" style="text-anchor:start;" font-family="'ChevinLight'">
<tspan font-size="20">
Firstname
</tspan>
<tspan font-size="20">
Lastname
</tspan>
</text>
<text style="text-anchor:start;" x="37.8" y="150" font-family="'ChevinLight'">
<tspan font-size="20">
Company Name
</tspan>
</text>
<xsl:variable name="code" select="Code"/>
<image xlink:href="LINK REDACTED" x="37.8" y="190" height="50" width="50"/>
<image xlink:href="LINK REDACTED" x="250" y="200" height="100"width="100"/>
</g>
<use href= "#mirrorpage" transform="translate (370.394 634.96) scale (-1 -1)"/>
</svg>
</fo:instream-foreign-object>
</fo:block>
</xsl:for-each>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
The error I am then receiving when I try to parse this is as follows:
[ERROR] svg graphic could not be built: file:/C:/Users/Events/Desktop/Angledtext/BadgePrinting/PDF/:-1
The URI '' specified on the element is invalid.
From my (limited) understanding, there is an issue with the parsing of the "#" in the use line. I have tried to research URI properties but I have to be honest, I am completely lost.
Any help, or even a pointer to some relevant material I can read would be greatly appreciated.
Thanks

XML Atom Pagination

I've been searching the internet hard to get clues how to paginate XML atom feed, but not been successful. How can I display the pagination for navigation on a page? i.e. pages 1 2 ..9
<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns:s="http://feed.example.com/services" xmlns="http://www.w3.org/2005/Atom">
<title type="text">org select - with 'Field' in name</title>
<id>http://feed.example.com/orga/srvic/name/Field</id>
<rights type="text">Copyright 2015</rights>
<updated>2010-05-09</updated>
<category term="Search" />
<logo>http://www.org.uk/orgcservices/docs/logo.jpg</logo>
<author>
<name>org select</name>
<uri>http://www.sampleorg.uk</uri>
<email>wbsrvcs#example.com</email>
</author>
<link rel="self" type="application/atom+xml" title="org select - Practices with 'Field' in name" href="http://feed.example.com/organisations/services/name/Field?apikey=12345" />
<link rel="first" type="application/atom+xml" title="first" length="1000" href="http://feed.example.com/organisations/services/name/Field?apikey=12345&page=1" />
<link rel="next" type="application/atom+xml" title="next" length="1000" href="http://feed.example.com/organisations/services/name/Field?apikey=12345&page=2" />
<link rel="last" type="application/atom+xml" title="last" length="1000" href="http://feed.example.com/organisations/services/name/Field?apikey=12345&page=9" />
<tracking xmlns="http://feed.example.com/services"><img style="border: 0; width: 1px; height: 1px;" alt="" src="http://webtrendsample.com/dfgfgh56dgd5/ddds.gif?fffuri=/organisations%2fservices%2fname%2fField&wt.js=no&wt.cg_n=feed"/></tracking>
<entry>
<id>http://feed.example.com/organisations/services/245645634</id>
<title type="text">Field Tree House</title>
<updated>2015-05-12T08:08:08Z</updated>
<link rel="self" title="Field Tree House Surgery" href="http://feed.example.com/organisations/services/24308?apikey=12345" />
<link rel="alternate" title="Field Tree House Surgery" href="http://www.org.uk/Srvcs/DR/Default.aspx?id=34343434" />
<content type="application/xml">
<s:organisationSummary>
<s:name>Field Tree House</s:name>
<s:odsCode>JD12345</s:odsCode>
<s:address>
<s:addressLine>Field Tree House</s:addressLine>
<s:addressLine>John Street</s:addressLine>
<s:addressLine>Lirkam</s:addressLine>
<s:addressLine>Stockion</s:addressLine>
<s:postcode>DWQ4 22GW</s:postcode>
</s:address>
<s:contact type="General">
<s:telephone>111 2223333444</s:telephone>
</s:contact>
</s:organisationSummary>
</content>
</entry>
<entry>
.
.
.
I don't have much experience with XML, so please bear with me. I have seen this: Pagination in feeds like ATOM and RSS? but this doesn't answer my query. Any ideas guys. I'd really appreciate it.
Thanks very much guys.
As you did not show what you tried, it is hard to figure out exactly what you want. If you want to compute the number of pages, given a page length, in an Atom feed, then it is simple arithmetics:
<xsl:variable name="page-length" select="10"/>
<xsl:template match="atom:feed">
<xsl:variable name="total" select="count(atom:entry)"/>
<xsl:choose>
<xsl:when test="$total eq 0">
<p>No entry.</p>
</xsl:when>
<xsl:otherwise>
<p>
<xsl:text>Pages: </xsl:text>
<xsl:value-of select="(($total - 1) idiv $page-length) + 1"/>
</p>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

how to manipulate XSLT file to only display one div instead of dl with dt's dd's and span's

I have a Section in a result from and XSLT file that is like this:
<dl class="price-list">
<dt> </dt>
<dd class="salesprice">
DKK <span class="pricethousands">2</span>
<span class="pricegroupingseparator">.</span>
<span class="pricehundreds">714</span>
<span class="pricedecimalseparator">,</span><span class="pricedecimals">40</span>
</dd>
</dl>
I have tried a few times to change the XSLT but i do not seem to be able to change it.
I'd like the result to become something like this or similar:
<div>
<p>DKK </p>
<p>2.714,40</p>
</div>
the xslt is currently using something like this:
<xsl:template match="/">
<xsl:variable name="html">
<xsl:for-each select="msxml:node-set($list)/product">
<xsl:call-template name="list-product">
<xsl:with-param name="list-product" select="."/>
<xsl:with-param name="list-vat" select="$list-vat"/>
....
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:copy-of select="$html" />
</xsl:template>
I hope you can help me to make this work. I know I haven't provided it all but as it is currently I can't provide more because I'm not allowed to.
<product>
<estocklevel></estocklevel>
<variantof></variantof>
<id></id>
<weightingram>137750</weightingram>
<unit></unit>
<volume>0</volume>
<discountgroup></discountgroup>
<manufactor></manufactor>
<deliverydate></deliverydate>
<url></url>
<texts></texts>
<name></name>
<longdescription></longdescription>
<shortdescription></shortdescription>
<htmltitle></htmltitle>
<metadescription></metadescription>
<metakeywords></metakeywords>
<group></group>
<alternativeitemid></alternativeitemid>
<alternativeitemrule></alternativeitemrule>
<duties></duties>
<priceinfo currency="" price="" standardsalesprice="" vatincludedinprice="False" vatrate="" quantity="">
<incvat price="">
<price></price>
<standardsalesprice></standardsalesprice>
<discountamount></discountamount>
<discountpercentage></discountpercentage>
<vat></vat>
</incvat>
<exvat price="">
<price></price>
<standardsalesprice></standardsalesprice>
<discountamount></discountamount>
<discountpercentage></discountpercentage>
<vat></vat>
</exvat>
</priceinfo>
<bulkdiscountpricelist></bulkdiscountpricelist>
<productcategories extra="productcategories"></productcategories>
<indicativedate extra="indicativedate"></indicativedate>
<oncampaign extra="oncampaign"></oncampaign>
<cnt extra="cnt"></cnt>
<weight extra="weight"></weight>
<misc extra="misc"></misc>
<dcurlv2 extra="dcurlv2"></dcurlv2>

XSLT 1.0 Grouping on multiple values on multiple levels

edited in response to comments *
Hello,
I am an XSLT noob and need some help. I am trying to do an filter/group combination with XSLT 1.0 (can't use XSLT 2.0 for this application).
Here is an example of the xml
<entry>
<item>
<name>Widget 2</name>
<rank>2</rank>
<types>
<type>Wood</type>
<type>Fixed</type>
<type>Old</type>
</types>
</item>
<item>
<name>Widget 1</name>
<rank>2</rank>
<types>
<type>Metal</type>
<type>Broken</type>
<type>Old</type>
</types>
</item>
<item>
<name>Widget 3</name>
<rank>1</rank>
<types>
<type>Metal</type>
<type>New</type>
</types>
</item>
</entry>
Now what I want to do is output html where I get a subset of the XML based on <type> and then group on rank. For example, if the user selects all items with the type Metal, the output should be:
<p class="nospace"><font color="#800000">
<b>Rank 1</b></font></p>
<li id="mylist"><b>Widget 3</b></li>
<br\>
<p class="nospace"><font color="#800000">
<b>Rank 2</b></font></p>
<li id="mylist"><b>Widget 1</b></li>
<br\>
of if the user user chooses the type Old the output would be
<p class="nospace"><font color="#800000">
<b>Rank 2</b></font></p>
<li id="mylist"><b>Widget 1</b></li>
<li id="mylist"><b>Widget 2</b></li>
<br\>
I can group using keys on rank along easily enough, but trying to do both is not working. Here is a sample of the xslt I have tried:
<xsl:param name="typeParam"/>
<xsl:key name="byRank" use="rank" match="item"/>
<xsl:for-each select="item[count(.|key('byRank',rank)[1])=1]">
<xsl:sort data-type="number" select="rank"/>
<xsl:for-each select="key('byRank',rank)">
<xsl:sort select="name"/>
<xsl:if test="count(rank)>0">
<p class="nospace"><font color="#800000"><b>Rank<xsl:value-of select="rank"/></b></font></p>
<xsl:for-each select="types[types=$typeParam]">
<li id="mylist"><b><xsl:value-of select="../name"/></b></li>
</xsl:for-each>
<br/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
The result I get from this is I do indeed get the subset of my xml that I want but it also displays all of the various rank values. I want to limit it to just the ranks of the type that is specified in $typeParam.
I have tried moving the for-each statement to earlier in the code as well as modifying the if statement to select for $typeParam but neither works. I have also tried concat-ing my key with rank and type but that doesn't seem to work either (It only works if the type in $typeParam is the first child under types).
Thanks
jeff
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kItemByRank" match="item" use="rank"/>
<xsl:param name="pType" select="'Old'"/>
<xsl:template match="entry">
<xsl:for-each select="item[count(.|key('kItemByRank',rank)[1])=1]">
<xsl:sort select="rank" data-type="number"/>
<xsl:variable name="vGroup" select="key('kItemByRank',rank)[
types/type = $pType
]"/>
<xsl:if test="$vGroup">
<p class="nospace">
<font color="#800000">
<b>
<xsl:value-of select="concat('Rank ',rank)"/>
</b>
</font>
</p>
<xsl:apply-templates select="$vGroup">
<xsl:sort select="name"/>
</xsl:apply-templates>
<br/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="item">
<li id="mylist">
<b>
<xsl:value-of select="name"/>
</b>
</li>
</xsl:template>
</xsl:stylesheet>
Output:
<p class="nospace">
<font color="#800000">
<b>Rank 1</b>
</font>
</p>
<li id="mylist">
<b>Widget 3</b>
</li>
<br />
<p class="nospace">
<font color="#800000">
<b>Rank 2</b>
</font>
</p>
<li id="mylist">
<b>Widget 1</b>
</li>
<br />
And whit pType param set to 'Old', output:
<p class="nospace">
<font color="#800000">
<b>Rank 2</b>
</font>
</p>
<li id="mylist">
<b>Widget 1</b>
</li>
<li id="mylist">
<b>Widget 2</b>
</li>
<br />

How do I retrieve a sibling by tag name in XSLT?

I am having an issue with the following, I need the ID to be of each promotiom:
Here is my XML:
<Promotions>
<Promotion>
<Category>Arts & Entertainment</Category>
<Client>Client 1</Client>
<ID>2</ID>
<Title>Get your Free 2</Title>
</Promotion>
<Promotion>
<Category>Client 1</Category>
<Client>Artsquest</Client>
<ID>4</ID>
<Title>Get your Free 4</Title>
</Promotion>
<Promotion>
<Category>Client 1</Category>
<Client>Artsquest</Client>
<ID>5</ID>
<Title>Get your Free 5</Title>
</Promotion>
<Promotion>
<Category>Community & Neighborhood</Category>
<Client>Client 2</Client>
<ID>1</ID>
<Title>Get your Free 1</Title>
</Promotion>
<Promotion>
<Category>Education</Category>
<Client>Client 3</Client>
<ID>3</ID>
<Title>Get Your Free 3</Title>
</Promotion>
<Promotion>
<Category>Home & Garden</Category>
<Client>Client 4</Client>
<ID>6</ID>
<Title>Get your Free 6</Title>
</Promotion>
</Promotions>
Here is my XSLT file:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:asp="remove">
<xsl:output method="html" indent="yes" />
<xsl:key name="categories" match="Category" use="." />
<xsl:key name="client" match="Client" use="." />
<xsl:key name="title" match="Title" use="." />
<xsl:template match="/">
<ul id="red" class="treeview-red">
<xsl:for-each select="/Promotions/Promotion/Category[
generate-id(.) = generate-id(key('categories', .)[1])
]">
<li>
<span>
<xsl:value-of select="."/>
</span>
<ul>
<xsl:call-template name="category-client">
<xsl:with-param name="category" select="."/>
</xsl:call-template>
</ul>
</li>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template name="category-client">
<xsl:param name="category" />
<xsl:for-each select="/Promotions/Promotion[Category=$category]/Client[
generate-id(.) = generate-id(key('client', .)[1])
]">
<li>
<span>
<xsl:value-of select="."/>
</span>
<ul>
<xsl:call-template name="category-client-title">
<xsl:with-param name="category" select="$category"/>
<xsl:with-param name="client" select="."/>
</xsl:call-template>
</ul>
</li>
</xsl:for-each>
</xsl:template>
<xsl:template name="category-client-title">
<xsl:param name="category" />
<xsl:param name="client" />
<xsl:for-each select="/Promotions/Promotion[Category=$category]/Title[
generate-id(.) = generate-id(key('title', .)[1])
]">
<li>
<span>
<asp:LinkButton ID ="{/Promotions/Promotion[Category=$category]/ID}" onclick="LinkClicked">
<xsl:value-of select="."/>
</asp:LinkButton>
</span>
</li>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
My issue is that the ID outputted if the client has multiple promotions in a category, I only get the first ID and it repeats for each, what is the best way to change this so that the ID matches the row the promotion title is coming from?
here is the output I am speaking of,I am so not grasping xsl...
<ul id="red" class="treeview-red" xmlns:asp="remove">
<li><span>Arts & Entertainment</span><ul>
<li><span>Client 1</span><ul>
<li><span><asp:LinkButton ID="2" onclick="LinkClicked">Get your Free 2</asp:LinkButton></span></li>
<li><span><asp:LinkButton ID="2" onclick="LinkClicked">Get your Free 4</asp:LinkButton></span></li>
<li><span><asp:LinkButton ID="2" onclick="LinkClicked">Get your Free 5</asp:LinkButton></span></li>
</ul>
</li>
</ul>
</li>
<li><span>Community & Neighborhood</span><ul>
<li><span>Client 2</span><ul>
<li><span><asp:LinkButton ID="1" onclick="LinkClicked">Get your Free 1</asp:LinkButton></span></li>
</ul>
</li>
</ul>
</li>
<li><span>Education</span><ul>
<li><span>Client 3</span><ul>
<li><span><asp:LinkButton ID="3" onclick="LinkClicked">Get Your Free 3</asp:LinkButton></span></li>
</ul>
</li>
</ul>
</li>
<li><span>Home & Garden</span><ul>
<li><span>Client 4</span><ul>
<li><span><asp:LinkButton ID="6" onclick="LinkClicked">Get your Free 6</asp:LinkButton></span></li>
</ul>
</li>
</ul>
</li>
</ul>
The correct XPath in this situation is:
<asp:LinkButton ID ="{../ID}" onclick="LinkClicked">
Since you are in <Title> context within the <xsl:for-each>, you must go up one level and fetch the <ID> from there. Your try
/Promotions/Promotion[Category=$category]/ID
fetches all <Promotion>s of a certain category and takes the first ID from the bunch, which is the same every time, naturally.
Just change
<asp:LinkButton ID ="{/Promotions/Promotion[Category=$category]/ID}" onclick="LinkClicked">
to
<asp:LinkButton ID ="{../ID}" onclick="LinkClicked">
Try something like position()=1 in your XSLT to select the first occurrence.