Use specific element for tab spaces - xslt

I want to use specific elements for tab spaces.
note: An end-nested-style character (<char type="endNestedStyleHere"/>) should be placed at the end of the show's title, which is marked by a space followed by one of the following codes: MVLSC, 16VLSC, MSC, 16VL, ML, MC, PGC, 16VL.
Input :
<table>
<tr>
<td> noon Nothing But Trailers MVLSC.</td>
</tr>
<tr>
<td> 7.10 Between Worlds 16VLSC 2018 Thriller.</td>
</tr>
</table>
Output should be:
<p type="Entry"><t/>noon<t/>Nothing But Trailers<char type="endNestedStyleHere"/> MVLSC.</p>
<p type="Entry"><t/>7.10<t/>Between Worlds<char type="endNestedStyleHere"/> 16VLSC 2018 Thriller.</p>
Tried code:
<xsl:template match="td[matches(.,'^\t*[0-9].*|\t*noon')]">
<p type="Entry">
<xsl:apply-templates/>
<p>
</xsl:template>
<xsl:template match="td/text()">
<xsl:if test="matches(.,'\t')">
<t/>
</xsl:if>
</xsl:template>

How about:
<xsl:template match="td">
<p type="Entry">
<xsl:analyze-string select="." regex="\t">
<xsl:matching-substring>
<t/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:analyze-string select="." regex=" (MVLSC|16VLSC|MSC|16VL|ML|MC|PGC)">
<xsl:matching-substring>
<char type="endNestedStyleHere"/>
<xsl:value-of select="." />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:non-matching-substring>
</xsl:analyze-string>
</p>
</xsl:template>

Related

for loop and use the value

I've the below line in XML.
<tb class="3">
<tr>
<td>
<b>English words </b>
</td>
<td>
<b>Arabic </b>
</td>
<td al="r">
<b>Arabic</b>
</td>
</tr>
<tr>
<td>bear </td>
<td>ḍam</td>
<td al="r">new</td>
</tr>
</tb>
Here is my xslt.
<xsl:template name="table" match="tb">
<table class="frame-all">
<xsl:call-template name="cols"/>
<xsl:apply-templates/>
</table>
</xsl:template>
<xsl:template name="cols">
<xsl:variable name="numbr" select="number(./#class)"/>
<xsl:variable name="colcnt" select="format-number(100 div $numbr,'##.#')"/>
<colgroup>
<!-- I want the condition here-->
</colgroup>
</xsl:template>
This gives me output of 33.3. And I want to create 3 cols(the class attribute value). And for each col the name should be increment value. as below.
<col name="1" width="33.3"/>
<col name="2" width="33.3"/>
<col name="3" width="33.3"/>
please let me know, how can i get the above result.
Thanks
Here is my answer.
<xsl:template name="table" match="tb">
<table class="frame-all">
<xsl:call-template name="cols"/>
<!--<xsl:apply-templates/>-->
</table>
</xsl:template>
<xsl:template name="colgroup">
<xsl:param name="count" select="./#cls"/>
<xsl:param name="final" select="1"/>
<xsl:variable name="colcnt" select="format-number(100 div number(./#cls),'##.#')"/>
<col class="colnum-{$final} colname-col{$final} colwidth-{$colcnt}"></col>
<xsl:if test="$final < $count">
<xsl:call-template name="colgroup">
<xsl:with-param name="final" select="$final +1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="cols">
<xsl:variable name="numbr" select="number(./#cls)"/>
<xsl:variable name="colcnt" select="format-number(100 div $numbr,'##.#')"/>
<colgroup>
<xsl:call-template name="colgroup"/>
</colgroup>
<xsl:for-each select="tr">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template match="tr">
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match="td">
<td>
<xsl:attribute name="align">
<xsl:choose>
<xsl:when test="./#al='r'">
<xsl:text>right</xsl:text>
</xsl:when>
<xsl:when test="./#al='c'">
<xsl:text>center</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>left</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates/>
</td>
</xsl:template>
If you are using XSLT 2.0, then one way to generate a specific number of elements, in your case col elements, is to use a variation of the xsl:for-each to do a specific number of iterations.
So, instead of doing <xsl:call-template name="colgroup"/> to call a recursive template, you could do this:
<colgroup>
<xsl:for-each select="1 to xs:integer($numbr)">
<col name="{.}" width="{$colcnt}"/>
</xsl:for-each>
</colgroup>
Note that you will need to define the xs namespace prefix in your stylesheet as follows
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">

Template match not entered

I've the below code in XML.
<?xml version="1.0" encoding="UTF-8"?>
<toa>
<title>TABLE OF HONG KONG LEGISLATION</title>
<subtitle>All references are to paragraph number</subtitle>
<toa-section>
<toa-div level="div1">
<title/>
<toa-entry>
<primary-entry>
<entry-name>Banking Ordinance (Cap.155)</entry-name>
<pgs>7.040</pgs>
</primary-entry>
</toa-entry>
</toa-div>
</toa-section>
</toa>
and the XSLT is as below.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:text disable-output-escaping="yes"><!DOCTYPE html>
</xsl:text>
<html>
<head>
<xsl:text disable-output-escaping="yes"><![CDATA[</meta>]]></xsl:text>
<title>TABLE OF LEGISLATION</title>
<link rel="stylesheet" href="C:\Users\u0138039\Desktop\In Progress\Company Law-Insolvency 2014 Edition_xml\XSLT\main.css" type="text/css" /><xsl:text disable-output-escaping="yes"><![CDATA[</link>]]></xsl:text>
</head>
<body>
<section class="tr_toa">
<xsl:call-template name="toa"></xsl:call-template>
</section>
</body>
</html>
</xsl:template>
<xsl:template name="toa">
<div class="toa">
<a name="CLI_TOL_01"> </a>
<xsl:apply-templates />
</div>
</xsl:template>
<xsl:template match="toa/title">
<div class="toa-title">
<xsl:value-of select="current()/content-style/text()"/>
</div>
</xsl:template>
<xsl:template match="toa-section">
<div class="toa-section">
<xsl:for-each select="current()/toa-div">
<xsl:call-template name="toa-div" />
</xsl:for-each>
</div>
</xsl:template>
<xsl:template match="toa-div" name="toa-div">
<xsl:variable name="divClass" select="concat('toa-div level-', current()/#level)"></xsl:variable>
<div class="{$divClass}">
<div class="toa-div-title">
<xsl:variable name="fontStyle">
<xsl:value-of select="concat('font-style-',title/content-style/#font-style)"/>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:value-of select="current()/title/content-style/text()"/>
</span>
</div>
<xsl:apply-templates select="toa-entry" />
</div>
</xsl:template>
<xsl:template match="toa-entry">
<xsl:choose>
<xsl:when test="not(preceding-sibling::toa-entry[1]/primary-entry/secondary-entry/node()) and position() != 1">
</xsl:when>
<xsl:otherwise>
<table class="toa-entry">
<tbody>
<xsl:apply-templates select="primary-entry" />
<xsl:if test="not(current()/primary-entry/secondary-entry/node())">
<xsl:apply-templates select="following-sibling::toa-entry[1]" mode="next"/>
</xsl:if>
</tbody>
</table>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="toa-entry" mode="next">
<xsl:apply-templates select="primary-entry"/>
<xsl:if test="not(current()/primary-entry/secondary-entry/node())">
<xsl:apply-templates select="following-sibling::toa-entry[1]" mode="next"/>
</xsl:if>
</xsl:template>
<xsl:template match="primary-entry">
<tr class="primary-entry">
<td class="entry-name">
<xsl:value-of select="current()/entry-name/text()"/>
</td>
<xsl:if test="current()/pgs/node()">
<td class="pgs" >
<xsl:variable name="pgcount" select="count(current()/pgs)"/>
<xsl:for-each select="current()/pgs">
<xsl:apply-templates select="./pgs"></xsl:apply-templates>
</xsl:for-each>
</td>
</xsl:if>
</tr>
<xsl:if test="current()/secondary-entry/node()">
<xsl:for-each select="current()/secondary-entry">
<tr class="secondary-entry">
<td class="entry-name">
<xsl:value-of select="current()/entry-name/text()"/>
</td>
<xsl:if test="current()/pgs/node()">
<td class="pgs" >
<xsl:variable name="pgcount" select="count(current()/pgs)"/>
<xsl:for-each select="current()/pgs">
<xsl:apply-templates></xsl:apply-templates>
</xsl:for-each>
</td>
</xsl:if>
</tr>
</xsl:for-each>
</xsl:if>
</xsl:template>
<xsl:template match="pgs">
<td class="pgs">
<xsl:analyze-string select="." regex="[^,\s]+">
<xsl:matching-substring>
<xsl:variable name="range" select="tokenize(.,'—')"/>
<xsl:variable name="pg" select="tokenize(.,'/')"/>
<xsl:choose>
<xsl:when test="contains($pg[3],'—')">
<xsl:variable name="range-pg" as="item()*">
<xsl:for-each select="$range">
<xsl:sequence select="tokenize(.,'/')"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="xs:integer($range-pg[3]) to xs:integer($range-pg[6])">
<a href="er:#HKWBV1_ORD_{
if (string(number($range-pg[1]))!='NaN') then
format-number(number($range-pg[1]),'00')
else
$range-pg[1]}/P{string-join($range-pg[position()=(1,2)],'/')}/{.}">
<xsl:value-of select="concat(string-join($range-pg[position()=(1,2)],'/'),'/',.)"/>
</a>
<xsl:text>, </xsl:text>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<a href="er:#HKWBV1_ORD_{
if (string(number($pg[1]))!='NaN') then
format-number(number($pg[1]),'00')
else
$pg[1]}/P{$pg[1]
}/{string-join($pg[position()>1],'/')}">
<xsl:value-of select="."/>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</td>
</xsl:template>
</xsl:stylesheet>
though i have written a template match for pgs, while debugging, the flow is not entering the template. Please let me know where am i going wrong.
Thanks
change
<xsl:template match="primary-entry">
<tr class="primary-entry">
<td class="entry-name">
<xsl:value-of select="current()/entry-name/text()"/>
</td>
<xsl:if test="current()/pgs/node()">
<td class="pgs" >
<xsl:variable name="pgcount" select="count(current()/pgs)"/>
<xsl:for-each select="current()/pgs">
<xsl:apply-templates select="./pgs"></xsl:apply-templates>
</xsl:for-each>
</td>
</xsl:if>
to
<xsl:template match="primary-entry">
<tr class="primary-entry">
<td class="entry-name">
<xsl:value-of select="current()/entry-name/text()"/>
</td>
<xsl:if test="current()/pgs/node()">
<xsl:apply-templates select="pgs"/>
</xsl:if>
and do the same for the secondary template.

text is getting repeated though the template is unique

I've the below piece of XML.
<section level="sect2" number-type="manual">
<para align="center">
<phrase>24-2</phrase>
<content-style font-style="italic">Destroying [or Damaging] property, contrary to section 60(1) of the Crimes Ordinance Cap 200, Laws of Hong Kong.</content-style>
</para>
</section>
and when i apply the below XSLT
<xsl:template name="para" match="section/para">
<xsl:choose>
<xsl:when test="current()/#align=center and ./#differentiation">
<div class="para align-{#align}">
<xsl:apply-templates/>
</div>
</xsl:when>
<xsl:when test="current()/#align=center and not(./#differentiation)">
<div class="para align1-{#align}">
<xsl:apply-templates/>
</div>
</xsl:when>
<xsl:when test="current()/#align and ./phrase[1]">
<div class="para new">
<xsl:apply-templates/>
</div>
</xsl:when>
<xsl:when test="current()/#align">
<div class="para align-{#align}">
<xsl:apply-templates/>
</div>
</xsl:when>
<xsl:otherwise>
<div class="para">
<xsl:apply-templates/>
</div>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text()">
<xsl:analyze-string select="." regex="(([Cc]hapter)\s(\d+))">
<xsl:matching-substring>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:analyze-string select="." regex="([0-9]+)\.([0-9]+)">
<xsl:matching-substring>
<xsl:variable name="num">
<xsl:value-of select="string-length(regex-group(2))"/>
</xsl:variable>
<a
href="{concat('er:#ABHK_CH_',format-number(number(regex-group(2)),'00'),'/P',format-number(number(regex-group(2)),'0'),'-',regex-group(3))}">
<xsl:value-of select="."/>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template name="phrase" match="phrase">
<xsl:variable name="phrl">
<xsl:value-of select="string-length(text())"/>
</xsl:variable>
<xsl:variable name="phrase">
<xsl:value-of select="concat('P',text())"/>
</xsl:variable>
<xsl:variable name="newphrase" select="translate($phrase,'.','-')"/>
<a>
<xsl:attribute name="name">
<xsl:value-of select="$newphrase">
</xsl:value-of>
</xsl:attribute>
</a>
<xsl:choose>
<xsl:when test="../#align">
<span class="phrase">
<xsl:value-of select="current()"/>
</span>
<span class="align-center">
<xsl:apply-templates select="following-sibling::node()[1]"/>
</span>
</xsl:when>
<xsl:when test="$phrl=3">
<span class="phrase">
<xsl:value-of select="current()"/>
</span>
<xsl:text disable-output-escaping="yes">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</xsl:text>
</xsl:when>
<xsl:when test="$phrl=4">
<span class="phrase">
<xsl:value-of select="current()"/>
</span>
<xsl:text disable-output-escaping="yes">&#160;&#160;&#160;&#160;</xsl:text>
</xsl:when>
<xsl:otherwise>
<span class="phrase">
<xsl:value-of select="current()"/>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="content-style">
<xsl:choose>
<xsl:when test="./#format">
<span class="{concat('format-',#format)}">
<xsl:apply-templates/>
</span>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="fontStyle">
<xsl:value-of select="concat('font-style-',#font-style)"/>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:choose>
<xsl:when test="../#align">
<xsl:value-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</xsl:otherwise>
</xsl:choose>
</span>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
the output i get is
24-2 Destroying [or Damaging] property, contrary to section 60(1) of the Crimes Ordinance Cap 200, Laws of Hong Kong. Destroying [or Damaging] property, contrary to section 60(1) of the Crimes Ordinance Cap 200, Laws of Hong Kong.
here Destroying [or Damaging] property, contrary to section 60(1) of the Crimes Ordinance Cap 200, Laws of Hong Kong.
is getting repeated though the template is called once. please let me know where am i going wrong.
Thanks
Within the template that matches the para element you are doing this
<xsl:apply-templates/>
This will look at both the child nodes of the para element and select templates that match them. As one of the child elements is content-style this will obviously apply the template that matches it.
However, within the template that matches phrase (which is the other child of para you do this (in the case where the para element has an align attribute, which is does here)
<xsl:apply-templates select="following-sibling::node()[1]"/>
The following sibling is the content-style, and so this will also use the template. Thus the template matching content-style gets called twice.
One solution is to the template matching para so that instead of doing <xsl:apply-templates/>, it explicitly ignores nodes that following phrase elements
<xsl:apply-templates select="*[not(preceding-sibling::*[1][local-name()='phrase'])]" />
Try this template for para instead
<xsl:template name="para" match="section/para">
<xsl:choose>
<xsl:when test="current()/#align=center and ./#differentiation">
<div class="para align-{#align}">
<xsl:apply-templates select="*[not(preceding-sibling::*[1][local-name()='phrase'])]" />
</div>
</xsl:when>
<xsl:when test="current()/#align=center and not(./#differentiation)">
<div class="para align1-{#align}">
<xsl:apply-templates select="*[not(preceding-sibling::*[1][local-name()='phrase'])]" />
</div>
</xsl:when>
<xsl:when test="current()/#align and ./phrase[1]">
<div class="para new">
<xsl:apply-templates select="*[not(preceding-sibling::*[1][local-name()='phrase'])]" />
</div>
</xsl:when>
<xsl:when test="current()/#align">
<div class="para align-{#align}">
<xsl:apply-templates select="*[not(preceding-sibling::*[1][local-name()='phrase'])]" />
</div>
</xsl:when>
<xsl:otherwise>
<div class="para">
<xsl:apply-templates/>
</div>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Tell XSLT to use explicit template rather than wildcard

I have the following template that will display a label, and then the value(s) following it.
<xsl:template match="*" mode="row">
<xsl:param name="title"/>
<tr>
<td width="180">
<xsl:value-of select="$title"/>: </td>
<td>
<xsl:choose>
<xsl:when test="./*">
<xsl:for-each select="./*">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
Called in the following instances:
<xsl:apply-templates select="Details/Detail/DateOfBirth" mode="row">
<xsl:with-param name="title">Date of birth</xsl:with-param>
</xsl:apply-templates>
<xsl:apply-templates select="Addresses" mode="row">
<xsl:with-param name="title">Address(s)</xsl:with-param>
</xsl:apply-templates>
Now - I don't want to have specify the label name each time I apply the template, that should be able to be determined by the node name.
So I create templates for each node to be applied:
<xsl:template match="DateOfBirth">
<xsl:apply-templates select="." mode="row">
<xsl:with-param name="title">Date Of Birth</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Addresses">
<xsl:apply-templates select="." mode="row">
<xsl:with-param name="title">Address(s)</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
And call these with:
<xsl:apply-templates select="Details/Detail/DateOfBirth" mode="row">
</xsl:apply-templates>
<xsl:apply-templates select="Addresses" mode="row">
</xsl:apply-templates>
But it is applying the wildcard template, leaving the label empty. Is there a way to tell it to prefer the explicit template?
I think the reason it preferred the wildcard template is that you were applying templates with mode="row", and your new template rules were in the unnamed mode.
I would do this by creating another mode, with very simple template rules:
<xsl:template match="DateOfBirth" mode="label">Date of Birth</xsl:template>
<xsl:template match="Addresses" mode="label">Address(es)</xsl:template>
and then instead of passing the parameter, you mode="row" template can do
<td width="180">
<xsl:apply-templates select="." mode="label"/>
</td>
Incidentally your xsl:choose also seems amenable to templatization:
<xsl:template match="*[*]" mode="row">
<tr>
<td width="180">
<xsl:apply-templates select="." mode="label"/>
</td>
<td>
<xsl:apply-templates select="*"/>
</td>
</tr>
</xsl:template>
<xsl:template match="*[not(*)]" mode="row">
<tr>
<td width="180">
<xsl:apply-templates select="." mode="label"/>
</td>
<td>
<xsl:apply-templates select="."/>
</td>
</tr>
</xsl:template>
Here's the hack I did:
<xsl:template match="*" mode="row">
<xsl:param name="title"/>
<xsl:choose>
<xsl:when test="$title=''">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:otherwise>
<tr>
<td width="180">
<xsl:value-of select="$title"/>: </td>
<td>
<xsl:choose>
<xsl:when test="./*">
<xsl:for-each select="./*">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
It checks if the title is blank, if it is (you're calling it for the first time), then it goes off and finds the explicit template for that node, which then re-calls it with the title.

XSLT Confusion with xsl:apply-templates

I have an XML file with this format:
<?xml version="1.0" encoding="utf-8" ?>
<OpacResult>
<valueObjects class="list">
<Catalog>
<notes>
Daily newsletter available via e-mail.
IP authenticated. Login not needed within firm.
</notes>
<title>Health law360. </title>
<url>http://health.law360.com/</url>
<catalogTitles class="list">
<CatalogTitle>
<uuid>e5e2bc53ac1001f808cddc29f93ecad8</uuid>
<timeChanged class="sql-timestamp">2010-12-14 09:17:10.707</timeChanged>
<timeEntered class="sql-timestamp">2010-12-14 09:17:10.707</timeEntered>
<whoChanged>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoChanged>
<whoEntered>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoEntered>
<updateSearchIndex>true</updateSearchIndex>
<corpId>RopesGray</corpId>
<catalogUuid>a20b6b4bac1001f86d28280ed0ebeb9e</catalogUuid>
<type>O</type>
<title>Law 360. Health law.</title>
</CatalogTitle>
<CatalogTitle>
<uuid>e5e2bc53ac1001f808cddc299ddfe49d</uuid>
<timeChanged class="sql-timestamp">2010-12-14 09:17:10.707</timeChanged>
<timeEntered class="sql-timestamp">2010-12-14 09:17:10.707</timeEntered>
<whoChanged>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoChanged>
<whoEntered>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoEntered>
<updateSearchIndex>true</updateSearchIndex>
<corpId>RopesGray</corpId>
<catalogUuid>a20b6b4bac1001f86d28280ed0ebeb9e</catalogUuid>
<type>O</type>
<title>Health law 360</title>
</CatalogTitle>
<CatalogTitle>
<uuid>e5e2bc53ac1001f808cddc29ec1d959b</uuid>
<timeChanged class="sql-timestamp">2010-12-14 09:17:10.707</timeChanged>
<timeEntered class="sql-timestamp">2010-12-14 09:17:10.707</timeEntered>
<whoChanged>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoChanged>
<whoEntered>B23DE2FFE8DD49B0B0A03D1FEB3E7DA2</whoEntered>
<updateSearchIndex>true</updateSearchIndex>
<corpId>RopesGray</corpId>
<catalogUuid>a20b6b4bac1001f86d28280ed0ebeb9e</catalogUuid>
<type>O</type>
<title>Health law three hundred sixty</title>
</CatalogTitle>
</catalogTitles>
<catalogUrls class="list"/>
<gmd>
<uuid>f8f123acc0a816070192e296a6a71715</uuid>
<timeChanged class="sql-timestamp">2006-10-10 15:23:37.813</timeChanged>
<timeEntered class="sql-timestamp">2005-01-27 00:00:00.0</timeEntered>
<whoChanged>25db9fcd3fd247f4a20485b40cc134ad</whoChanged>
<whoEntered>user</whoEntered>
<updateSearchIndex>true</updateSearchIndex>
<corpId>RopesGray</corpId>
<isRuleDefault>false</isRuleDefault>
<ruleName>text</ruleName>
<term>electronic resource</term>
<preferCollection>false</preferCollection>
<isTechnicalManual>false</isTechnicalManual>
<sip2IsMagnetic>false</sip2IsMagnetic>
</gmd>
<issues class="list"/>
</Catalog>
</valueObjects>
</OpacResult>
As you can see, there are other elements under sibling nodes, but I don't care about these and only want to see the first one.
I'm using this code to call a template with the string of desired elements as the parameter
and a template to loop through the asterisk-delimited string parameter: (title*url*notes*)
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="columns" />
<xsl:template match="/OpacResult/valueObjects">
<html>
<body>
<table border="1">
<!-- Header row -->
<tr>
<xsl:call-template name="print-headers">
<xsl:with-param name="columns" select="$columns"/>
</xsl:call-template>
</tr>
<!-- Value rows -->
<xsl:for-each select="Catalog">
<tr>
<xsl:call-template name="print-values">
<xsl:with-param name="columns" select="$columns"/>
</xsl:call-template>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
<!-- Split up string of column names and create header field names based on element names-->
<xsl:template name="print-headers">
<xsl:param name="columns"/>
<xsl:variable name="newList" select="$columns"/>
<xsl:variable name="first" select="substring-before($newList, '*')" />
<xsl:variable name="remaining" select="substring-after($newList, '*')" />
<th>
<xsl:apply-templates select="Catalog/*[name()=$first]">
<xsl:with-param name="header">true</xsl:with-param>
</xsl:apply-templates>
</th>
<xsl:if test="$remaining">
<xsl:call-template name="print-headers">
<xsl:with-param name="columns" select="$remaining"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="print-values">
<xsl:param name="columns"/>
<xsl:variable name="newList" select="$columns"/>
<xsl:variable name="first" select="substring-before($newList, '*')" />
<xsl:variable name="remaining" select="substring-after($newList, '*')" />
<td>
<xsl:apply-templates select="Catalog/*[name()=$first]"/>
</td>
<xsl:if test="$remaining">
<xsl:call-template name="print-values">
<xsl:with-param name="columns" select="$remaining"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="title">
<xsl:param name="header"/>
<xsl:choose>
<xsl:when test="$header='true'">
<xsl:text>Title</xsl:text>
</xsl:when>
<xsl:otherwise>
<a>
<xsl:attribute name="href">
<xsl:value-of select="//*[name()='url']"/>
</xsl:attribute>
<xsl:value-of select="//*[name()='title']"/>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="url">
<xsl:param name="header"/>
<xsl:choose>
<xsl:when test="$header='true'">
<xsl:text>URL</xsl:text>
</xsl:when>
<xsl:otherwise>
<a>
<xsl:attribute name="href">
<xsl:value-of select="//*[name()='url']"/>
</xsl:attribute>
<xsl:value-of select="//*[name()='url']"/>
</a>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="notes">
<xsl:param name="header"/>
<xsl:choose>
<xsl:when test="$header='true'">
<xsl:text>Notes</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="//*[name()='notes']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="holdingNotes">
<xsl:param name="header"/>
<xsl:choose>
<xsl:when test="$header='true'">
<xsl:text>Holding Notes</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="//*[name()='holdingNotes']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="relatedUrl">
<xsl:param name="header"/>
<xsl:choose>
<xsl:when test="$header='true'">
<xsl:text>Related URL</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="//*[name()='relatedUrl']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="bibliographicType/hasDataFile">
<xsl:param name="header"/>
<xsl:choose>
<xsl:when test="$header='true'">
<xsl:text>File</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="Catalog/*[name()='hasDataFile']"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
The only way I can access this template is to use the //*[name()=$first] syntax to extract the value of the element based on the name from the $first parameter.
Any help is greatly appreciated. Thanks very much in advance. Not including the full XML as there are thousands of lines of unnecessary text.
This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:h="header"
exclude-result-prefixes="h">
<h:h>
<title>Title</title>
<url>URL</url>
<notes>Notes</notes>
</h:h>
<xsl:param name="pColumns" select="'title url notes'"/>
<xsl:template match="/OpacResult/valueObjects">
<html>
<body>
<table border="1">
<tr>
<xsl:apply-templates
select="document('')/*/h:h"
mode="filter"/>
</tr>
<xsl:apply-templates/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Catalog">
<tr>
<xsl:call-template name="filter"/>
</tr>
</xsl:template>
<xsl:template match="h:h/*">
<th>
<xsl:value-of select="."/>
</th>
</xsl:template>
<xsl:template match="Catalog/*">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
<xsl:template match="node()" mode="filter" name="filter">
<xsl:apply-templates select="*[contains(
concat(' ',$pColumns,' '),
concat(' ',name(),' '))]">
<xsl:sort select="substring-before(
concat(' ',$pColumns,' '),
concat(' ',name(),' '))"/>
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
Output:
<html>
<body>
<table border="1">
<tr>
<th>Title</th>
<th>URL</th>
<th>Notes</th>
</tr>
<tr>
<td>Health law360. </td>
<td>http://health.law360.com/</td>
<td> Daily newsletter available via e-mail.
IP authenticated. Login not needed within firm. </td>
</tr>
</table>
</body>
</html>
Note: Inline data for headers, pseudo sequence parameter for filtering and sorting, modes not for processing the same element in different way but for processing different elements in the same way also.
I've found a solution, but I'm sure it's not the best way to do it. Within the templates for each of my expected fields, I have added:
<xsl:if test=position()=1">
.. process data here ..
</xsl:if>
Ideally, there would be a way to tell this to process only the first element it finds:
<th>
<xsl:apply-templates select="//*[name()=$first]">
<xsl:with-param name="header">true</xsl:with-param>
</xsl:apply-templates>
</th>
Edit: As I suspected, this will not work when there is more than one Catalog element to parse. So instead of grabbing the first element for each catalog parent element, it's grabbing the first element in the document every time