I am absolutely a beginner to XSLT. I am using xslt to convert data to a HTML table. I need help to avoid some duplicates.
I have tried several fixes but non of then worked.
This is my XML file.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<Identifikasjon>
<Internref>12909524760066</Internref>
</Identifikasjon>
<NavnAdresse>
<Status>0</Status>
<StatusDato>2009-10-27</StatusDato>
<Fodselsdato>1901-01-01</Fodselsdato>
<Navn>DEMO PERSON</Navn>
<Adresse>TESTEGATA 76</Adresse>
<Postnr>4950</Postnr>
<Poststed>RISØR</Poststed>
<Kommune>RISØR</Kommune>
<Fylke>AUST-AGDER</Fylke>
<Alder>118</Alder>
<Kjonn>MANN</Kjonn>
</NavnAdresse>
<BetaDetaljer>
<RegistrertDato>2001-12-10</RegistrertDato>
<BetaGruppeKode>NE</BetaGruppeKode>
<BetaGruppeTekst>Negative</BetaGruppeTekst>
<BetaType>UL</BetaType>
<BetaTekst>UTLEGG</BetaTekst>
<BetaBelop>2111</BetaBelop>
<KildeKode>LØSØ</KildeKode>
<KildeTekst>LØSØREREGISTERET</KildeTekst>
<KildeReferansenr>12345</KildeReferansenr>
<Kreditor>TESTKREDITOREN</Kreditor>
</BetaDetaljer>
<Ligning>
<SkatteAr>2018</SkatteAr>
<Formue>1111111</Formue>
<EndringFormue>117.39</EndringFormue>
<Inntekt>511111</Inntekt>
<EndringInntekt>0.0</EndringInntekt>
<Skatt>111111</Skatt>
<SkatteKlasse>1E</SkatteKlasse>
<Kommunenr>301</Kommunenr>
<KommuneNavn>OSLO</KommuneNavn>
<BruttoInntekt>0</BruttoInntekt>
<Gjeldsgrad1>0.0</Gjeldsgrad1>
<Gjeldsgrad2>0.0</Gjeldsgrad2>
</Ligning>
<Ligning>
<SkatteAr>2017</SkatteAr>
<Formue>511111</Formue>
<EndringFormue>0.0</EndringFormue>
<Inntekt>511111</Inntekt>
<EndringInntekt>0.0</EndringInntekt>
<Skatt>111111</Skatt>
<SkatteKlasse>1E</SkatteKlasse>
<Kommunenr>1534</Kommunenr>
<KommuneNavn>HARAM</KommuneNavn>
<BruttoInntekt>0</BruttoInntekt>
<Gjeldsgrad1>0.0</Gjeldsgrad1>
<Gjeldsgrad2>0.0</Gjeldsgrad2>
</Ligning>
<Ligning>
<SkatteAr>2016</SkatteAr>
<Formue>511111</Formue>
<EndringFormue>0.0</EndringFormue>
<Inntekt>511111</Inntekt>
<EndringInntekt>0.0</EndringInntekt>
<Skatt>111111</Skatt>
<SkatteKlasse>1E</SkatteKlasse>
<Kommunenr>1534</Kommunenr>
<KommuneNavn>HARAM</KommuneNavn>
<BruttoInntekt>0</BruttoInntekt>
<Gjeldsgrad1>0.0</Gjeldsgrad1>
<Gjeldsgrad2>0.0</Gjeldsgrad2>
</Ligning>
<NaringsInteresser>
<Orgnr>937340303</Orgnr>
<StatusKode>A</StatusKode>
<StatusTekst>Aktivt</StatusTekst>
<Navn>SVAR DIREKTE AS</Navn>
<SelskForm>AS</SelskForm>
<Rolle>Eier</Rolle>
<Eierandel>5.0</Eierandel>
</NaringsInteresser>
<NaringsInteresser>
<Orgnr>931024280</Orgnr>
<StatusKode>A</StatusKode>
<StatusTekst>Aktivt</StatusTekst>
<Navn>HELT NYTT FORETAK AS</Navn>
<SelskForm>AS</SelskForm>
<Rolle>Ansvar</Rolle>
<Eierandel>0.0</Eierandel>
<VervKode>3</VervKode>
<VervTekst>Styremedlem</VervTekst>
</NaringsInteresser>
<Meldinger>
<MeldingsKode>30</MeldingsKode>
<MeldingsTekst>Navn/adresse-historikk ikke funnet på forespurt objekt.</MeldingsTekst>
</Meldinger>
</root>
This is the xslt code I am using.
<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>
<title>Wash Result</title>
</head>
<body>
<h2>Wash Result</h2>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="All">
<xsl:apply-templates select="Identifikasjon" />
<xsl:apply-templates select="Ligning" />
</xsl:template>
<xsl:template match="Identifikasjon">
<div class="accordion">
<div class="option">
<input type="checkbox" id="toggle1" class="toggle" />
<label class="title" for="toggle1">
Identifikasjon
</label>
<div class="content ">
<div class="display-inline">
<p>
<xsl:if test="Orgnr">
<span class="mr-3">
Orgnr: <strong>
<xsl:value-of select="Orgnr" />
</strong>
</span>
</xsl:if>
<xsl:if test="Dunsnr">
<span>
Dunsnr: <strong>
<xsl:value-of select="Dunsnr" />
</strong>
</span>
</xsl:if>
<xsl:if test="Internref">
<span>
Internref: <strong>
<xsl:value-of select="Internref" />
</strong>
</span>
</xsl:if>
</p>
</div>
</div>
</div>
</div>
</xsl:template>
<xsl:template match="Ligning">
<div class="accordion">
<div class="option">
<input type="checkbox" id="toggleLigning" class="toggle" />
<label class="title" for="toggleLigning">
Ligning
</label>
<div class="content">
<table border="1">
<tr>
<th>SkatteAr</th>
<th>Formue</th>
<th>EndringFormue</th>
<th>Inntekt</th>
<th>EndringInntekt</th>
<th>Skatt</th>
<th>SkatteKlasse</th>
<th>Kommunenr</th>
<th>KommuneNavn</th>
<th>BruttoInntekt</th>
<th>Gjeldsgrad1</th>
<th>Gjeldsgrad2</th>
</tr>
<xsl:for-each select="/root/Ligning">
<tr>
<td>
<xsl:value-of select="SkatteAr" />
</td>
<td>
<xsl:value-of select="Formue" />
</td>
<td>
<xsl:value-of select="EndringFormue" />
</td>
<td>
<xsl:value-of select="Inntekt" />
</td>
<td>
<xsl:value-of select="EndringInntekt" />
</td>
<td>
<xsl:value-of select="Skatt" />
</td>
<td>
<xsl:value-of select="SkatteKlasse" />
</td>
<td>
<xsl:value-of select="Kommunenr" />
</td>
<td>
<xsl:value-of select="KommuneNavn" />
</td>
<td>
<xsl:value-of select="BruttoInntekt" />
</td>
<td>
<xsl:value-of select="Gjeldsgrad1" />
</td>
<td>
<xsl:value-of select="Gjeldsgrad2" />
</td>
</tr>
</xsl:for-each>
</table>
</div>
</div>
</div>
</xsl:template>
The result is as follows.
result from the code
I want to stop duplicating the lines. (Ligning)
Related
I have the following XML with name, say, "screen.xml":
<tc:transform xmlns:tc="http://www.w2.prg/1999/XSL/Transform" version="1.0">
<tc:blockTemplate blockTitle="Court/Agency">
<link flush="true" href="./customimages/customBlockStylesheet.css" rel="stylesheet" type="text/css"/>
<!-- BEGIN Court Information Content -->
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<!-- Control Row -->
<tr>
<td class="altFieldColor" height="0" width="20%"/>
<td class="altFieldColor" height="0" width="10"/>
<td class="altFieldColor" height="0" width="25%"/>
<td class="altFieldColor" height="0" width="2"/>
<td class="altFieldColor" height="0" width="10"/>
<td class="altFieldColor" height="0" width="20%"/>
<td class="altFieldColor" height="0" width="10"/>
<td class="altFieldColor" height="0" width="100%"/>
</tr>
<tr>
<td colspan="8">
<img border="0" height="2" src="./customimages/spacer.gif" width="1"/>
</td>
</tr>
<tr>
<td class="altFieldColor" height="40">
<tc:label category="DISP" name="CoreDocketNumber"/>:</td>
<td class="altFieldColor" width="10">
<img border="0" height="1" src="./customimages/spacer.gif" width="10"/>
</td>
<td class="altFieldColor" nowrap="true">
**<tc:field category="DISP" name="CoreDocketNumber"/>**
</td>
<td width="2">
<img border="0" height="1" src="./customimages/spacer.gif" width="2"/>
</td>
<td class="altFieldColor" width="10">
<img border="0" height="1" src="./customimages/spacer.gif" width="10"/>
</td>
<td class="altFieldColor" height="40">
<tc:label category="DISP" name="CoreCourt"/>:</td>
<td class="altFieldColor" width="10">
<img border="0" height="1" src="./customimages/spacer.gif" width="10"/>
</td>
<td class="altFieldColor" nowrap="true">
**<tc:field category="DISP" name="CoreCourt"/>**
</td>
</tr>
</table>
<!-- END Court Information Content -->
</tc:blockTemplate>
</tc:transform>
I am trying to write an XSL that will mostly ignore the html tags and only look at the tags with name "tc:field" and give me the following:
<H1>screen.xml</H1>
<ul>
<li>DISP.CoreDocketNumber</li>
<li>DISP.CoreCourt</li>
</ul>
The DISP is the value of the category attribute of the tc:field tag and CoreDocketNumber is the value of the name attribute.
Here's my attempt at the XSL
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tc="http://www/w2.prg/1999/XSL/Tansform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="html" indent="yes"/>
<xsl:template match="#*|node()">
<ul>
<xsl:apply-templates select="tc:field"/>
</ul>
</xsl:template>
<xsl:template match="tc:field">
<li><xsl:value-of select="#category"/>.<xsl:value-of select="#name"/></li>
</xsl:template>
</xsl:stylesheet>
I only get the following output when I apply the xsl to the xml:
<ul xmlns:tc="http://www/w2.prg/1999/XSL/Tansform" xmlns="http://www.w3.org/1999/xhtml"></ul>
I am not sure I am handling the tc namespace correctly. Any guidance would be greatly appreciated.
Try something like:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tc="http://www.w2.prg/1999/XSL/Transform"
exclude-result-prefixes="tc">
<xsl:template match="/">
<html>
<body>
<H1>screen.xml</H1>
<ul>
<xsl:apply-templates select="//tc:field"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="tc:field">
<li>
<xsl:value-of select="#category"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="#name"/>
</li>
</xsl:template>
</xsl:stylesheet>
I'm having some issue with my xslt code and I was Wondering if someone could take a look. I think the problem is with the date formatting but i'm not sure.
I need to format a datetime into a day and month.
this is my code:
<xsl:stylesheet
version="1.0"
exclude-result-prefixes="x d xsl msxsl cmswrt"
xmlns:x="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">
<xsl:template name="NewsAndEvents" match="Row[#Style='NewsAndEvents']" mode="itemstyle">
<xsl:variable name="SafeImageUrl">
<xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
<xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DisplayTitle">
<xsl:call-template name="OuterTemplate.GetTitle">
<xsl:with-param name="Title" select="#Title"/>
<xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="ArticleDate">
<xsl:value-of select="#SongDate"/>
</xsl:variable>
<xsl:if test="string-length($SafeImageUrl) != 0">
<div class="event-contain">
<div class="event-img pull-right">
<div class="white-box">
<h1><xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'MMMM')"/></h1>
<h2><xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'd')"/></h2>
</div>
<img src="{$SafeImageUrl}" title="{#ImageUrlAltText}">
<xsl:if test="$ImageWidth != ''">
<xsl:attribute name="width">
<xsl:value-of select="$ImageWidth" />
</xsl:attribute>
</xsl:if>
<xsl:if test="$ImageHeight != ''">
<xsl:attribute name="height">
<xsl:value-of select="$ImageHeight" />
</xsl:attribute>
</xsl:if>
</img>
</div>
<div class="text-sec pull-right">
<header>
<hgroup>
<h3 class="ttl md fnt-bld blue"> <xsl:value-of select="$DisplayTitle"/> </h3>
<h4 class="ttl sm fnt-bld blue-mob"> <xsl:value-of select="#SongDescription"/> </h4>
</hgroup>
</header>
<div class="row dynamic-text-contain pull-right">
<p class="ttl xs">
<span class="display-on-mob"><xsl:value-of select="#NewsDescription" /></span>
</p>
</div>
<div class="row">
<div class="display-all read-more-eruim no-mob">
<div class="display-more open-link">
<a>
<i class="icon-icons2-50"></i>
<p>
<span class="btn-text">Show All</span>
<i class="icon-icons2-10 left-arrow" id="arrow"></i>
</p>
</a>
</div>
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="line"></div>
</div>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Tnx For the Help Yotam.
I Have a Solution If any one ever has this problem:
the thing is that:
<xsl:value-of select="ddwrt:FormatDate(string($ArticleDate),1037, 'd')"/>
is the wrong syntax and should be :
<xsl:value-of select="ddwrt:FormatDateTime(string($ArticleDate),1037, 'd')"/>
Now, another thing is that it returns the value as: dd/mm/yyyy and I only wanted the day so I used a sub string function like so:
<xsl:value-of select="substring-before(ddwrt:FormatDateTime(string($ArticleDate),1037, 'd'),'/')"/>
This Solved me this issue :)
I am trying to create a standings board for a soccer league. I am very new to XSLT and blundering my way around.
Below is the data format that I have
Data:
<sports-statistics>
<sports-team-stats>
<date year="2013" month="4" date="23" day="2"/>
<time hour="16" minute="00" second="59" timezone="Eastern" utc-hour="-4" utc-minute="00"/>
<version number="2"/>
<league global-id="513" name="Youth Soccer League" alias="YSL" display-name=""/>
<season year="2013" id="1" description="2013 YSL Season"/>
<soccer-ifb-team-stats>
<ifb-team>
<team-info global-id="11270" id="1869" location="Tulsa" name="Astecs" alias="TUL" display-name="Astecs"/>
<split id="0" type="all" name="All Games">
<games-played games="1"/>
<record wins="0" losses="0" ties="1" percentage=".500"/>
<minutes minutes="90"/>
<goals goals="1" headed="0" kicked="1" />
<opponent-goals goals="1"/>
<own-goals goals="0"/>
<assists assists="1"/>
<opponent-assists assists="1"/>
<shots shots="18"/>
<opponent-shots shots="10"/>
<shots-on-goal shots="7"/>
<opponent-shots-on-goal shots="4"/>
</split>
<split id="302" type="home" name="Home Games">
<games-played games="1"/>
<record wins="0" losses="0" ties="1" percentage=".500"/>
<minutes minutes="90"/>
<goals goals="1" headed="0" kicked="1" />
<opponent-goals goals="1"/>
<own-goals goals="0"/>
<assists assists="1"/>
<opponent-assists assists="1"/>
<shots shots="18"/>
<opponent-shots shots="10"/>
<shots-on-goal shots="7"/>
<opponent-shots-on-goal shots="4"/>
</split>
</ifb-team>
</soccer-ifb-team-stats>
</sports-team-stats>
</sports-statistics>
Here is my code so far.
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
<xsl:output method="html" indent="yes" encoding = "utf-8" standalone = "yes"/>
<xsl:variable name="allGames">
<map gametype="All Games" />
</xsl:variable>
<xsl:variable name="gameMapping" select="msxsl:node-set($allGames)/*" />
<xsl:template match="/">
<html>
<head>
<meta charset="utf-8" />
<title> Standings</title>
</head>
<body>
<h2> TEST </h2>
<table border="1" style="width: 100%;">
<tr>
<th>Club</th>
<th>GP</th> <!--Games Played-->
<th>W</th> <!--Wins-->
<th>L</th> <!--Loss-->
<th>T</th> <!--Ties-->
<th>%</th> <!--Win Loss Ratio-->
</tr>
<xsl:apply-templates select="//ifb-team/split[#name = 'All Games']" />
</table>
</body>
</html>
</xsl:template>
<xsl:template match="ifb-team/split">
<xsl:variable name="ti" select="../team-info" />
<tr>
<td>
<xsl:value-of select="$ti/#display-name" />
</td>
<td>
<xsl:value-of select="following-sibling::games-played/#games"/>
</td>
<td>
<xsl:value-of select="following-sibling::record/#wins"/>
</td>
<td>
<xsl:value-of select="following-sibling::record/#losses"/>
</td>
<td>
<xsl:value-of select="following-sibling::record/#ties"/>
</td>
<td>
<xsl:value-of select="following-sibling::record/#percentage"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
All I am getting is a table with the display name and nothing else. I am not getting any of the siblings data. What am I missing?
This is simple:
games-played is not a sibling -- it is a child of split.
The same is true for record.
Therefore, use:
<td>
<xsl:value-of select="games-played/#games"/>
</td>
<td>
<xsl:value-of select="record/#wins"/>
</td>
<td>
<xsl:value-of select="record/#losses"/>
</td>
<td>
<xsl:value-of select="record/#ties"/>
</td>
<td>
<xsl:value-of select="record/#percentage"/>
</td>
Ok, I'm working through some simple tutorials from here:
http://www.cch.kcl.ac.uk/legacy/teaching/7aavdh06/xslt/html/module_06.html
The first exercise involves creating a transformation that produces a certain output. Unfortunately, although I'm close, I get an unwanted element at the start. i.e.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xhtml"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" />
<xsl:template match="/div/placeName">
<html>
<head />
<body>
<Table>
<tr>
<td>Place Name</td>
<td>
<xsl:value-of select="name" />
</td>
</tr>
<tr>
<td>Place Name (regularised)</td>
<td>
<xsl:value-of select="#reg" />
</td>
</tr>
<tr>
<td>National Grid Reference</td>
<td>
<xsl:value-of select="#key" />
</td>
</tr>
<tr>
<td>Type of building/monument</td>
<td>
<xsl:value-of select="settlement/#type" />
</td>
</tr>
</Table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
but the output I'm getting is:
Location
Place Name Old Warden
Place Name (regularised) Old Warden, St Leonard
National Grid Reference TL 137 443
Type of building/monument Parish church
The rest is fine but the 'Location' is unwanted. The source XML is at the link above. Any idea how I stop the unwanted text appearing? Or, better still, tell me where I'm going wrong! :)
Edit: Here is the output
<?xml version="1.0" encoding="utf-8" ?>
Location
<!DOCTYPE html SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<body>
<table>
<tr>
<td>Place Name</td>
<td>Old Warden</td>
</tr>
<tr>
<td>Place Name (regularised)</td>
<td>Old Warden, St Leonard</td>
</tr>
<tr>
<td>National Grid Reference</td>
<td>TL 137 443</td>
</tr>
<tr>
<td>Type of building/monument</td>
<td>Parish church</td>
</tr>
</table>
</body>
</html>
As Stivel mentions, the "Location" text does come from the head element in your XML.
<div type="location">
<head n="I">Location</head>
<placeName reg="Old Warden, St Leonard" key="TL 137 443">
The reason it is appearing is because of XSTL's built-in templates which it uses when you do not specify a match for an element it is looking for in your XSLT.
You can read up on built-in templates at the W3C page but in short, if XSLT can't find a match it will either continue processing the element's children (without copying the element), or in the case of text or attributes, output the value.
XSLT will start by looking for a match for the document element first, and if you have not provided a template, it will continue looking for a template for the root element, and then its children, and so on.
In your case, you have not provided a template to match anything until /div/placeName, this means XSLT will use the built-in template for the div element. This has two children; head and placeName. You have a template it can use for placeName, but not head and so the built-in template ends up outputing the text for head because you have not told it anything otherwise.
The solution is to simply to add a template to ignore the head element
<xsl:template match="/div/head" />
Here is the full XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xhtml"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" indent="yes" />
<xsl:template match="/div/head" />
<xsl:template match="/div/placeName">
<html>
<head />
<body>
<Table>
<tr>
<td>Place Name</td>
<td>
<xsl:value-of select="name" />
</td>
</tr>
<tr>
<td>Place Name (regularised)</td>
<td>
<xsl:value-of select="#reg" />
</td>
</tr>
<tr>
<td>National Grid Reference</td>
<td>
<xsl:value-of select="#key" />
</td>
</tr>
<tr>
<td>Type of building/monument</td>
<td>
<xsl:value-of select="settlement/#type" />
</td>
</tr>
</Table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
When you use this, this should give the output you need.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xhtml" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:template match="div">
<xsl:apply-templates select="placeName"/>
</xsl:template>
<xsl:template match="placeName">
<html>
<head />
<body>
<Table>
<tr>
<td>Place Name</td>
<td>
<xsl:value-of select="name" />
</td>
</tr>
<tr>
<td>Place Name (regularised)</td>
<td>
<xsl:value-of select="#reg" />
</td>
</tr>
<tr>
<td>National Grid Reference</td>
<td>
<xsl:value-of select="#key" />
</td>
</tr>
<tr>
<td>Type of building/monument</td>
<td>
<xsl:value-of select="settlement/#type" />
</td>
</tr>
</Table>
</body>
</html>
</xsl:template>
Probably your <head/> may refer
<head n="I">Location</head>
remove <head/> in xsl and check that.
I need to turn
<question>
<static><![CDATA[Static Data]]></static>
<debit-row />
<debit-row />
<credit-row />
<header><![CDATA[Header HTML 1]]></header>
<debit-row />
<debit-row />
<credit-row />
</question>
into
<p>Static Data</p>
<ul>
<li>
<table>
<tr><td> debit row </td></tr>
<tr><td> credit row </td></tr>
<tr><td> credit row </td></tr>
</table>
</li>
<li> Header HTML 1
<table>
<tr><td> debit row </td></tr>
<tr><td> debit row </td></tr>
<tr><td> credit row </td></tr>
</table>
</li>
</ul>
Essentially, either a header or a debit-row indicates the start of a new chunk. Each chunk is a list item. Each set or rows is a table (as a rule, credit rows always come last so it's easy to tell when to start the table).
XSLT and XPATH seem very difficult and I'm having a very hard time looking up anything that I want to do at all, so if anyone has an excellent reference, I would appreciate that too.
I've started out with this xsl:
<xsl:template match="question">
<xsl:apply-templates select="static|header|debit-row[preceding-sibling::*[1] != header]" />
</xsl:template>
This is not a good start, because the templates are not applied to any debit-row at all, but they should be applied to the very first debit-row (it does not have a header element preceding it). Is that expression wrong?
Even if I get that to work, I need to find a way to say "Open a <ul> if this is the very first header or debit-row," and I'm not sure how to do that when applying the header/debit-row template. debit-row each has its own xml to be applied too (it needs a table row and td). I also have to open and close the table appropriately before the first debit-row and after the last credit-row.
I would seriously appreciate any help as I am stuck even getting the simple xpath expression above to work correctly.
I. XSLT 1.0 solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kFollowing"
match="*[not(self::static or self::header)]"
use="generate-id(preceding-sibling::*
[self::static
or
self::header
][1]
)"/>
<xsl:template match="/*[static]">
<p><xsl:value-of select="static"/></p>
<ul>
<xsl:apply-templates select="static|header"/>
</ul>
</xsl:template>
<xsl:template match="static|header">
<li>
<xsl:value-of select=
"concat(self::header, '
')"/>
<table>
<xsl:apply-templates
select="key('kFollowing', generate-id())"/>
</table>
</li>
</xsl:template>
<xsl:template match=
"*/*[not(self::static or self::header)]">
<tr>
<td>
<xsl:value-of select=
"translate(name(),'-', ' ')"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<question>
<static><![CDATA[Static Data]]></static>
<debit-row />
<debit-row />
<credit-row />
<header><![CDATA[Header HTML 1]]></header>
<debit-row />
<debit-row />
<credit-row />
</question>
produces the wanted, correct result:
<p>Static Data</p>
<ul>
<li>
<table>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>credit row</td>
</tr>
</table>
</li>
<li>Header HTML 1
<table>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>credit row</td>
</tr>
</table>
</li>
</ul>
Explanation: Positional grouping using a key to define all elements that belong to a group.
II. XSLT 2.0 solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*[static]">
<p><xsl:value-of select="static"/></p>
<ul>
<xsl:for-each-group select="*"
group-starting-with="static|header">
<li>
<xsl:value-of separator="
" select=
"current-group()[1][self::header], ''"/>
<table>
<xsl:apply-templates
select="current-group()[position() gt 1]"/>
</table>
</li>
</xsl:for-each-group>
</ul>
</xsl:template>
<xsl:template match=
"*/*[not(self::static or self::header)]">
<tr>
<td>
<xsl:value-of select=
"translate(name(),'-', ' ')"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
when this XSLT 2.0 transformation is applied to the same XML document (above), again the same, correct result is produced:
<p>Static Data</p>
<ul>
<li>
<table>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>credit row</td>
</tr>
</table>
</li>
<li>Header HTML 1
<table>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>debit row</td>
</tr>
<tr>
<td>credit row</td>
</tr>
</table>
</li>
</ul>
Explanation: Using the XSLT 2.0 <xsl:for-each-group> instruction with a group-starting-with attribute. Also using the standard XSLT 2.0 function current-group().