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>
Related
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)
Here is some XSL script:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msa="http://www.publictalksoftware.co.uk/msa">
<xsl:output method="html" indent="yes" version="4.01"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
doctype-public="//W3C//DTD XHTML 1.0 Transitional//EN"/>
<xsl:variable name="DutyHistory" select="document('DutyAssignHistory.XML')"/>
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<body>
<xsl:for-each select="MeetingWorkBook/Meeting">
<p>
<xsl:value-of select ="Date/#ThisWeek"/>
</p>
<xsl:variable name="Week" select="Date/#ThisWeek"/>
<table>
<tr>
<td>Sound</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='1' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Platform</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='5' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Left Mike</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='7' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Right Mike</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='8' and #IndexType='Fixed']"/>
</td>
</tr>
<tr>
<td>Public Talk Chairman</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='4' and #IndexType='Custom']"/>
</td>
</tr>
<tr>
<td>Watchtower Reader</td>
<td>
<xsl:value-of select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment[#Index='5' and #IndexType='Custom']"/>
</td>
</tr>
</table>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
As you can see it is linking in another XML document for reference. Here is one example of that linked in file:
<?xml version="1.0" encoding="utf-8"?>
<DutyAssignmentHistory xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.publictalksoftware.co.uk/msa">
<DutyAssignments>
<DutyAssignmentEntry Date="2018-01-04" Week="W20180101" Template="0" Mode="Midweek">
<Assignment Index="2" IndexType="Fixed">Name 1</Assignment>
<Assignment Index="5" IndexType="Fixed">Name 2</Assignment>
<Assignment Index="7" IndexType="Fixed">Name 3</Assignment>
<Assignment Index="8" IndexType="Fixed">Name 4</Assignment>
<Assignment Index="13" IndexType="Fixed">Name 5</Assignment>
<Assignment Index="14" IndexType="Fixed">Name 6</Assignment>
</DutyAssignmentEntry>
</DutyAssignments>
</DutyAssignmentHistory>
Potentially a user might want to reference the information in the XML and display it however they like but I am wanting to show them the simplest method.
As you can see there are several criteria:
Week (WYYYYMMDD)
Mode (Midweek, Weekend or Weekly)
Template(0 or higher)
The above will filter to the right week of assignments. Then, to identify the actual assignment:
Index (numeric value)
IndexType (Fixed, CustomFixed or Custom)
Can I use templates in any way (perhaps with variables) to simplify the code as it is getting repetative?
You could use a template and pass parameters, or in XSLT 2.0 or higher you could also define a function, which makes it much easier to use and saves some typing. But for what you are currently doing, a variable and some predicate filters seems to be the most simple and easy.
The most simple and easy way would be to bind a variable with the weekend assignments, and then apply your predicate filter to select the one with the #Index and #IndexType:
<xsl:variable name="Week" select="Date/#ThisWeek"/>
<xsl:variable name="weekend-assignments"
select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments
/msa:DutyAssignmentEntry[#Week=$Week and #Mode='Weekend']/msa:Assignment"/>
<table>
<tr>
<td>Sound</td>
<td>
<xsl:value-of select="$weekend-assignments[#Index='1' and #IndexType='Fixed']"/>
</td>
</tr>
If you make the variable hold an unfiltered set of Assignment elements, you could perform all of the filtering in the predicates:
<xsl:variable name="Week" select="Date/#ThisWeek"/>
<xsl:variable name="assignments"
select="$DutyHistory/msa:DutyAssignmentHistory/msa:DutyAssignments
/msa:DutyAssignmentEntry/msa:Assignment"/>
<table>
<tr>
<td>Sound</td>
<td>
<xsl:value-of
select="$assignments[#Index='1' and #IndexType='Fixed']
[..[#Week=$Week and #Mode='Weekend' and #Template='0']]"/>
</td>
</tr>
If you want to consolidate the logic for generating the columns, you could define a template for msa:Assignment:
<xsl:template match="msa:Assignment">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
And then use it like this:
<table>
<tr>
<td>Sound</td>
<xsl:apply-templates select="$weekend-assignments[#Index='1' and #IndexType='Fixed']"/>
If you want to consolidate the logic for generating rows, you could define a template for msa:Assignment and send in a parameter for the first column:
<xsl:template match="msa:Assignment">
<xsl:param name="label"/>
<tr>
<td><xsl:value-of select="$label"/></td>
<td>
<xsl:value-of select="."/>
</td>
</tr>
</xsl:template>
And then use it like this:
<table>
<xsl:apply-templates select="$weekend-assignments[#Index='1' and #IndexType='Fixed']">
<xsl:with-param name="label" select="'Sound'"/>
</xsl:apply-templates>
I have the following xml:
input
<page>
<group category="cat1">
<item fileunder="#">.45 colt</item>
<item fileunder="#">8 queens</item>
<item fileunder="#">9 lives</item>
<item fileunder="#">99 bottles of beer</item>
<item fileunder="A">An innocent man</item>
<item fileunder="A">Academy awards</item>
<item fileunder="B">Before the dawn</item>
</group>
<group category="cat2">
<item fileunder="R">Rows of houses</item>
</group>
</page>
The input items are already sorted.
desired output
I want to produce a 3-column HTML table for every group, with a subheading (a 3-column spanning cell) for each distinct fileunder, optimally presented in a top-down, then-next-column (the items are already sorted):
<table>
<tr><td colspan="3">#</td></tr>
<tr><td>.45 colt</td><td>9 lives</td><td>99 bottles of beer</td></tr>
<tr><td>8 queens</td></tr>
<tr><td colspan="3">A</td></tr>
<tr><td>An innocent man</td><td>Academy awards</td></tr>
<tr><td colspan="3">B</td></tr>
<tr><td>Before the dawn</td></tr>
</table>
<table>
<tr><td colspan="3">R</td></tr>
<tr><td>Rows of houses</td></tr>
</table>
I can live if the items are presented as left-to-right, then-next-row.
What I have so far is:
current xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="itm_grp" match="/page/group/item" use="concat(../#category,':',#fileunder)"/>
<xsl:template match="page/group">
<table>
<xsl:for-each select="item[.=key('itm_grp',concat(../#category,':',#fileunder))[1]]">
<tr><td colspan="3"><xsl:value-of select="#fileunder"/></td></tr>
<xsl:variable name="nodeset" select="key('itm_grp',concat(../#category,':',#fileunder))"/>
<xsl:for-each select="$nodeset[position() mod 3=1]">
<tr>
<td><xsl:value-of select="."/></td>
<td><xsl:value-of select="following-sibling::item[1]"/></td>
<td><xsl:value-of select="following-sibling::item[2]"/></td>
</tr>
</xsl:for-each>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
which produces a left-to-right, then-next-row output (non-optimal); however, the following-sibling selects produce a “bleed-through” effect:
#
.45 colt 8 queens 9 lives
99 bottles of beer An innocent man Academy awards
A
An innocent man Academy awards Before the dawn
B
Before the dawn
R
Rows of houses
As you can see, fileunder # has two A items, and fileunder A has one B item.
So, my question is:
How can I produce the desired output (column-wise)?
If I can't do that, how can I have the row-wise output avoiding the “bleeding”?
Please note that I have very little experience with XSLT, so if my code is blatantly inefficient/idiotic/whatever, please feel free to educate me by replacing all of it!
NB: XSLT version 1, so apparently no index-of function is available.
There is a slight contradiction between your narrative and your listed expected output. You have asked for top-down, then left-right column fill order, which you have so in the listing for the non-empty values, but not for the empties. This spatial order implies that a whole column must be filled out before the next column can begin. I have assumed that your listing was a mistake and what your really want in output is ...
<table>
<tr>
<td colspan="3">#</td>
</tr>
<tr>
<td>.45 colt</td>
<td>9 lives</td>
<td>&npsp;</td>
</tr>
<tr>
<td>8 queens</td>
<td>99 bottles of beer</td>
<td>&npsp;</td>
</tr>
<tr>
<td colspan="3">A</td>
</tr>
<tr>
<td>An innocent man</td>
<td>Academy awards</td>
<td>&npsp;</td>
</tr>
<tr>
<td colspan="3">B</td>
</tr>
<tr>
<td>Before the dawn</td>
<td>&npsp;</td>
<td>&npsp;</td>
</tr>
</table>
<table>
<tr>
<td colspan="3">R</td>
</tr>
<tr>
<td>Rows of houses</td>
<td>&npsp;</td>
<td>&npsp;</td>
</tr>
</table>
... which is consistent top-down, then left-right column fill order.
This XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" doctype-system="about:legacy-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="kItemByFile" match="item" use="concat(../#category,':',#fileunder)"/>
<xsl:template match="/">
<html lang="en">
<head><title>Songs</title></head>
<body>
<xsl:apply-templates select="*/group" />
</body>
</html>
</xsl:template>
<xsl:template match="group">
<xsl:variable name="cat" select="concat(#category,':')" />
<table>
<xsl:apply-templates select="item[
generate-id() = generate-id(key('kItemByFile',concat($cat,#fileunder))[1])]"
mode="group-head" />
</table>
</xsl:template>
<xsl:template match="item" mode="group-head">
<xsl:variable name="items"
select="key('kItemByFile',concat(../#category,':',#fileunder))" />
<xsl:variable name="row-count" select="ceiling( count($items) div 3)" />
<tr><td colspan="3"><xsl:value-of select="#fileunder" /></td></tr>
<xsl:for-each select="$items[position() <= $row-count]">
<xsl:variable name="pos" select="position()" />
<xsl:apply-templates select="." mode="row">
<xsl:with-param name="items" select="$items" />
<xsl:with-param name="row" select="$pos" />
<xsl:with-param name="row-count" select="$row-count" />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="item" mode="row">
<xsl:param name="items" select="/.." />
<xsl:param name="row" select="1" />
<xsl:param name="row-count" select="1" />
<tr>
<xsl:apply-templates select="
$items[(position() mod $row-count) = ($row mod $row-count)]" mode="td" />
<xsl:variable name="full-cols" select="floor((count($items) div $row-count))" />
<xsl:variable name="part-col" select="number($row <
((count($items) mod $row-count) + 1))" />
<xsl:variable name="empties" select="3 - ($full-cols + $part-col)" />
<xsl:for-each select="(document('')/*/*)[position() <= $empties]">
<xsl:call-template name="empty-cell" />
</xsl:for-each>
</tr>
</xsl:template>
<xsl:template match="item" mode="td">
<td><xsl:value-of select="." /></td>
</xsl:template>
<xsl:template name="empty-cell">
<td> </td>
</xsl:template>
</xsl:stylesheet>
...when applied to this input...
<page>
<group category="cat1">
<item fileunder="#">.45 colt</item>
<item fileunder="#">8 queens</item>
<item fileunder="#">9 lives</item>
<item fileunder="#">99 bottles of beer</item>
<item fileunder="A">An innocent man</item>
<item fileunder="A">Academy awards</item>
<item fileunder="B">Before the dawn</item>
</group>
<group category="cat2">
<item fileunder="R">Rows of houses</item>
</group>
</page>
...yields...
<!DOCTYPE html SYSTEM "about:legacy-compat">
<html lang="en">
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Songs</title>
</head>
<body>
<table>
<tr>
<td colspan="3">#</td>
</tr>
<tr>
<td>.45 colt</td>
<td>9 lives</td>
<td> </td>
</tr>
<tr>
<td>8 queens</td>
<td>99 bottles of beer</td>
<td> </td>
</tr>
<tr>
<td colspan="3">A</td>
</tr>
<tr>
<td>An innocent man</td>
<td>Academy awards</td>
<td> </td>
</tr>
<tr>
<td colspan="3">B</td>
</tr>
<tr>
<td>Before the dawn</td>
<td> </td>
<td> </td>
</tr>
</table>
<table>
<tr>
<td colspan="3">R</td>
</tr>
<tr>
<td>Rows of houses</td>
<td> </td>
<td> </td>
</tr>
</table>
</body>
</html>
Note
For the empty cells in the output, when viewing the lexical HTML, you will get either or the literal white space equivalent. It is XSLT processor implementation dependant, but should not cause you any concern because it is model-equivalent.
Easiest way to fix that:
<xsl:variable name="header" select="#fileunder"/>
...
<xsl:value-of select="following-sibling::item[#fileunder=$header][1]"/>
<xsl:value-of select="following-sibling::item[#fileunder=$header][2]"/>
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 some to help oon generating the XSL file for my XML Data.
Here is my XML Data
<?xml-stylesheet href="C:\Style.xsl" type="text/xsl" ?>
<xml>
<ApproverRoles OperationType="RemovedUser" xmlns="http://tempuri.org/">
<UserName>Bhupathiraju, Venkata</UserName><UserRole>IT Owner</UserRole><RoleDescription>Role Owner
</RoleDescription><UserRoleID>138</UserRoleID></ApproverRoles>
<ApproverRoles OperationType="RemovedUser" xmlns="http://tempuri.org/">
<UserName>Bhupathiraju, Venkata</UserName><UserRole>Business Owner</UserRole>
<RoleDescription>Role Owner</RoleDescription><UserRoleID>136</UserRoleID></ApproverRoles>
<ApproverRoles OperationType="RemovedUser" xmlns="http://tempuri.org/"><UserName>Amperayeni, Kiran K</UserName>
<UserRole>IT Owner</UserRole><RoleDescription>asdasdasd</RoleDescription><UserRoleID>97</UserRoleID>
</ApproverRoles>
<ApproverRoles OperationType="RemovedUser" xmlns="http://tempuri.org/"><UserName>Amperayeni, Kiran K</UserName>
<UserRole>IT Owner</UserRole><RoleDescription>i</RoleDescription><UserRoleID>135</UserRoleID></ApproverRoles>
</xml>
My XSL file is below
<?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>
<head>
<title>User Management</title>
</head>
<body>
<table width="600" border="1" style='font-family:Calibri;font-size:10pt;background-color:#FFFFFF;border-color:#ccccff'>
<tr bgcolor = "#ccccff" style='font-weight:bold;'>
<td colspan="3">Proposed Users :</td>
</tr>
<tr bgcolor = "#cccccc" style='font-weight:bold;'>
<td>User Name</td>
<td>Role</td>
<td>Role Qualifier</td>
</tr>
<xsl:for-each select="//ns1:ApproverRoles" >
<tr>
<td>
<xsl:value-of select="UserName" />
</td>
<td>
<xsl:value-of select="UserRole" />
</td>
<td>
<xsl:value-of select="RoleDescription" />
</td>
</tr>
</xsl:for-each>
<tr bgcolor = "#ccccff" style='font-weight:bold;'>
<td colspan="3">Removed Users :</td>
</tr>
<tr bgcolor = "#cccccc" style='font-weight:bold;'>
<td>User Name</td>
<td>Role</td>
<td>Role Qualifier</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet >
You are not correctly dealing with the default namespace present in the input document. If you do not associate a prefix to the corresponding namespace uri, the XSLT processor will search for elements in no namespace. Actually, the elements in your input document, are all in the namespace http://tempuri.org/.
So, you need first to declare the namespace prefix in the transform:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="http://tempuri.org/">
Then, you have to use the prefix accordingly. For instance:
<xsl:for-each select="//ns1:ApproverRoles" >
<tr>
<td>
<xsl:value-of select="ns1:UserName" />
</td>
<td>
<xsl:value-of select="ns1:UserRole" />
</td>
<td>
<xsl:value-of select="ns1:RoleDescription" />
</td>
</tr>
</xsl:for-each>