Test for following sibling not having argument - xslt

Consider the following xml file:
<main>
<sub>
<div n="1"/>
<div n="2"/>
<div n="3"/>
<div n="-">
</sub>
<sub>
<div n="1"/>
<div n="2"/>
<div/>
</sub>
<sub>
<div n="1"/>
<div n="2"/>
<div n="-"/>
</sub>
</main>
I want to output only the value of the last #n that is a digit and is followed either by a div with no #n or one with #n = '-'. The following test in a template that matches divs outputs all #ns containing digits...
<xsl:if test="
matches(#n, '[0-9]') and
following-sibling::div[not(#n) or #n='-']
">
I also tried:
<xsl:if test="
matches(#n, '[0-9]') and
(not(following-sibling::div[#n]) or
following-sibling::div[#n='-'])
">
Am I missing something?

Related

xsl loop with new name for template tag

I am trying to use a loop iteration in xslt. I want to loop through all the text with tei of "orgName", and generate a different popover-body for each one. I hope it would be something like (div class="Org-popover-body-1),(div class="Org-popover-body-2)... What should I put in ??? Thanks beforehand.
<xsl:template match="tei:orgName">
<xsl:for-each select="orgName">
<a class="orgName" id="orgNameinfo" data-toggle="popover-2" data-trigger="fcours" data-popover-content-2="#a2" data-placement="right">
<xsl:attribute name="href">
<xsl:text>#</xsl:text>
<xsl:value-of select="#key" />
</xsl:attribute>
</a>
<div id="a2" class="hidden">
<div class="popover-heading2">Orgnization Information <span style="float:right;cursor:pointer;" class="fa fa-times" data-toggle="popover"></span>
</div>
<div class="Org-popover-body-???">
</div>
</div>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:template>
I think what you need are Attribute Value Templates, so you would write this...
<div class="Org-popover-body-{position()}">
You probably want to do this in the id of the hidden div to (to avoid multiple divs with the same id)
<div id="a{position()}" class="hidden">
And similarly in the data-popover-content-2 attribute
... data-popover-content-2="#a{position()}" ...

How to automatically assign value to an attribute using XSLT in for-each loop?

In a for-each XSLT loop I construct an HTML structure of the form:
<div class="panel-group" id="accordion1" role="tablist" aria-multiselectable="true">
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading001">
...
</div>
</div>
</div>
Is it possible in that loop to generate the suffix of the attributes id and assign to it? So that in first loop the IDs become "accordion1" and "heading001", in the second loop become "accordion2" and "heading002", etc? And if so, can you provide an example?
in your for each loop, example for the id do something like below
<xsl:attribute name="id">
<xsl:value-of select="concat('accordion', position()" />
</xsl:attribute>

xslt matching all nodes prior to a specific node

I am trying to match all the nodes before a specific node. Input XML
<story>
<content>
<p>This is the text I want</p>
<p>This is the text I want</p>
<p>This is the text I want</p>
<ul>
<li></li>
...
</ul>
....
....
</content>
</story>
With That as my input XML, I am trying and failing to grab all the <p> tags prior to the <ul> tags and render them. There could be 0 <p> tags or infinite. Any thoughts on how to do this with XSLT 1.0? Thanks!
/story/content/p[not(preceding-sibling::ul)]
Use:
//p[not(preceding::ul or ancestor::ul)]
This is generally wrong:
//p[not(preceding-sibling::ul)]
because it doesnt select p elements that come before any ul, but aren't siblings to any ul.
For example, given this XML document:
<story>
<div>
<p>Must be selected</p>
</div>
<ul>
<li><p>Must not be selected</p></li>
</ul>
<content>
<p>Must not be selected</p>
<div>
<p>Must not be selected</p>
</div>
<p>Must not be selected</p>
<p>Must not be selected</p>
<ul>
<li></li>
<li><p>This must not be selected</p></li>
</ul>
....
....
</content>
</story>
the above wrong expression selects:
<p>Must not be selected</p>
<p>Must not be selected</p>
<p>Must not be selected</p>
and doesn't select the wanted element:
<p>Must be selected</p>
But the correct expression at the start of this answer selects just the wanted p element:
<p>Must be selected</p>

How can these XSLT documents be DRY-ed

I have made two pages and now I wonder if I can DRY them.
Here the XSLT:
Frontpage: http://pastebin.com/yuZL913W
dagboek-page: http://pastebin.com/6FGYvpvf (Edited)
Roelof
Sorry one of the links is wrong.
I edited this.
My question is how to DRY these so I can reuse parts. Only the <div id="posts"> is different.
I think I understand the fill in the blanks but it is one big xslt file. Is this possible without named templates and call-templates
Here is one way -- what I call "Fill-in-the-blanks" to separate content from processing and to parameterize processing:
Rendering file (c:/temp/delete/nc3.xml):
<html xmlns:gen="gen:gen">
<gen:data from="params" mode="top"/>
<body >
<div id="outer">
<div id="container">
<div id="search">
<form method="get" id="searchform" action="http://www.notepadchaos.com/">
<input type="text" value="" name="s" id="s" class="txtField" />
<input type="submit" id="searchsubmit" class="btnSearch" value="Find It " />
</form>
</div>
<div id="title">
<h2>Tamara Wobben</h2>
</div>
</div>
<div id="content">
<div class="col01">
<div class="post">
<h3> <gen:data from="entry/title"/> </h3>
<div class="post-inner">
<gen:data from="section/entry/tekst" />
</div></div></div>
<div class="side-columns">
<div class="col02">
<div class="pages">
<!-- hier komen de losse pagina's -->
</div>
<div class="pages-bottom"></div>
<div class="categories-upper"></div>
<div class="categories">
<!-- hier komt het menu -->
</div>
<div class="categories-btm"></div>
</div>
<div class ="col03">
<div class="recent-post" >
<!-- hier komen de recente posts -->
</div>
<div class="postit-bottom"></div>
</div>
</div>
<br style="clear:both" />
</div>
<gen:data from="params" mode="down"/>
</div>
</body>
</html>
Data file (c:/temp/delete/data.xml):
<data>
<params>
<today>2011-12-29</today>
<current-time>22:17</current-time>
<this-year>2011</this-year>
<this-month>12</this-month>
<this-day>29</this-day>
<timezone>+01:00</timezone>
<website-name>Tamara Wobben</website-name>
<page-title>frontpage</page-title>
<root>http://test.tamarawobben.nl</root>
<workspace>http://test.tamarawobben.nl/workspace</workspace>
<root-page>frontpage</root-page>
<current-page>frontpage</current-page>
<current-page-id>6</current-page-id>
<current-path>/?debug=xml</current-path>
<parent-path>/</parent-path>
<current-url>http://test.tamarawobben.nl/?debug=xml</current-url>
<upload-limit>2097152</upload-limit>
<symphony-version>2.2.5</symphony-version>
<cookie-username>xxxx</cookie-username>
<cookie-pass>xxxxx</cookie-pass>
<site-mode>live</site-mode>
</params>
<events />
<image>
<section id="7" handle="images">Images</section>
<entry id="13">
<image size="22 KB" path="/images" type="image/jpeg">
<filename>img_5874.jpg</filename>
<meta creation="2011-12-19T18:40:04+01:00" width="400" height="267" />
</image>
</entry>
</image>
<recent-posts>
<section id="9" handle="dagboek">Dagboek</section>
<entry id="15">
<datum time="00:00" weekday="2">2005-02-22</datum>
<titel handle="7-weken-echo">7 weken echo</titel>
</entry>
</recent-posts>
<section>
<section id="6" handle="sections">Sections</section>
<entry id="12">
<title handle="even-voorstellen">Even Voorstellen</title>
<tekst><p>FLOAT : img_5874.jpg</p> 55 56<p>Naam : Tamara Wobben<br /> 57Geboorte gewicht : 2000 gram<br /> 58Geboorte lengte : 44 cm.<br /> 59Geboortedatum : 1 september 2005 </p>
</tekst>
</entry>
</section>
</data>
XSLT code:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:gen="gen:gen" exclude-result-prefixes="gen">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pFormPath" select=
"'file:///c:/temp/delete/nc3.xml'"/>
<xsl:param name="pDataPath" select=
"'file:///c:/temp/delete/data.xml'"/>
<xsl:variable name="vFormDoc" select="document($pFormPath)"/>
<xsl:variable name="vDataDoc" select="document($pDataPath)"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$vFormDoc/*"/>
</xsl:template>
<xsl:template match=
"gen:data
[#from='params'
and
#mode='top'
]">
<!-- Use $vDataDoc to populate this -->
T O P S T U F
</xsl:template>
<xsl:template match=
"gen:data[#from='entry/Title']">
<!-- Use $vDataDoc to populate this -->
E N T R Y T I T L E
</xsl:template>
<xsl:template match=
"gen:data[#from='section/entry/tekst']">
<!-- Use $vDataDoc to populate this -->
S E C T I O N E N T R Y T E X T
</xsl:template>
<xsl:template match=
"gen:data
[#from='params'
and
#mode='down'
]">
<!-- Use $vDataDoc to populate this -->
D O W N S T U F
</xsl:template>
</xsl:stylesheet>
Source XML file (not used):
<t/>
When the above transformation is performed on any XML file (not used), the rendering file is populated with data from the data file. The templates that process the placeholder gen:data elements, are dummy but still demonstrate how this processing works.
The result of the processing:
<html xmlns:gen="gen:gen">
T O P S T U F
<body>
<div id="outer">
<div id="container">
<div id="search">
<form method="get" id="searchform" action="http://www.notepadchaos.com/"><input type="text" value="" name="s" id="s" class="txtField"><input type="submit" id="searchsubmit" class="btnSearch" value="Find It "></form>
</div>
<div id="title">
<h2>Tamara Wobben</h2>
</div>
</div>
<div id="content">
<div class="col01">
<div class="post">
<h3>
<gen:data from="entry/title"></gen:data>
</h3>
<div class="post-inner">
S E C T I O N E N T R Y T E X T
</div>
</div>
</div>
<div class="side-columns">
<div class="col02">
<div class="pages">
<!-- hier komen de losse pagina's -->
</div>
<div class="pages-bottom"></div>
<div class="categories-upper"></div>
<div class="categories">
<!-- hier komt het menu -->
</div>
<div class="categories-btm"></div>
</div>
<div class="col03">
<div class="recent-post">
<!-- hier komen de recente posts -->
</div>
<div class="postit-bottom"></div>
</div>
</div><br style="clear:both"></div>
D O W N S T U F
</div>
</body>
</html>
Do note:
This code can populate any rendering document (path passed as an external parameter) using the data from any data document (again path passed as an external parameter). Thus it becomes possible to create different outputs/formats populated with different data.
The placeholders (gen:data elements) to be replaced with "live content" can have different format and semantics -- no limits to one's imagination.
Editors (non-XSLT experts) can work on one or more rendering documents independently from each other and from the XSLT developers.
A higher degree of reusability, flexibility and maintainability is achieved.

Using XSLT, how to turn each tag into a div with a class matching the tag name?

Using XSLT, I'd like to be able to transform this :
<doc>
<tag1>AAA</tag1>
Hello !
<tag2>BBB</tag2>
</doc>
into this :
<div class="doc">
<div class="tag1">AAA</div>
Hello !
<div class="tag2">BBB</div>
</div>
...but without specifying explicitly any tag name in the stylesheet (there are too many in the real world)
What would be the best way to do this ?
Something along the lines of
<xslt:template match="*">
<div class="{local-name()}">
<xsl:apply-templates />
</div>
</xslt:template>