XSLT: count tei:lb and print them - xslt

I have some TEI-files with a rather diverse structure. A rather complete example of special cases is the following:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml" schematypens="http://relaxng.org/ns/structure/1.0"?>
<?xml-model href="http://www.tei-c.org/release/xml/tei/custom/schema/relaxng/tei_all.rng" type="application/xml"
schematypens="http://purl.oclc.org/dsdl/schematron"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0">
<teiHeader>
<fileDesc>
<titleStmt>
<title>Title</title>
</titleStmt>
<publicationStmt>
<p>Publication Information</p>
</publicationStmt>
<sourceDesc>
<p>Information about the source</p>
</sourceDesc>
</fileDesc>
</teiHeader>
<text>
<body>
<div type="section" n="13">
<p><lb/>[Art. 13]
<orig>¶ </orig><choice><orig>Jn</orig><reg>In</reg></choice> <choice><orig>ſoͤlcher</orig><reg>sölcher</reg></choice> fürgezogener <choice><orig>Berathſchlagung</orig><reg>Berathschlagung</reg></choice> des
<lb/>Friedens<orig> /</orig> haben <choice><orig>ſich</orig><reg>sich</reg></choice> gleich als bald auß der erfarnuß<orig> /</orig>
<lb/><choice><orig>vnd</orig><reg>und</reg></choice> dem jenigen<supplied>,</supplied> <choice><orig>ſo</orig><reg>so</reg></choice> <choice><orig>hieuor</orig><reg>hievor</reg></choice> fürgangen<choice><orig> /</orig><reg>,</reg></choice> der <choice><orig>Chůrfürſten</orig><reg>Churfürsten</reg></choice>
<lb/>Rehte<choice><orig> /</orig><reg>,</reg></choice> <choice><orig>erſcheynende</orig><reg>erscheynende</reg></choice> <choice><orig>Fürſten</orig><reg>Fürsten</reg></choice><choice><orig> /</orig><reg>,</reg></choice> Stendt<choice><orig> /</orig><reg>,</reg></choice> <choice><orig>Bottſchafften</orig><reg>Bottschafften</reg></choice>
<lb/><choice><orig>vnd</orig><reg>und</reg></choice> <choice><orig>Geſandten</orig><reg>Gesandten</reg></choice> erinnert<choice><orig>.</orig><reg>:</reg></choice> Dieweyl auff allen
<lb/>von <choice><orig>Dreyſſig</orig><reg>Dreyssig</reg></choice> oder mehr Jaren<note type="crit_app"><rs type="bibl" ref="#drta_jr_20_4">DRTA.JR 20,4, S. 3107, Z. 29</rs>: <hi rend="italic">danach folgend</hi> der.</note> gehaltenen <choice><orig><w>Reychß
<lb rend="trennstrich"/>taͤgen</w></orig><reg><w>Reychß<lb rend="trennstrich"/>tägen</w></reg></choice> <choice><orig>vnd</orig><reg>und</reg></choice> etlichen mehr Particular <choice><orig>verſamblungen</orig><reg>versamblungen</reg></choice><note type="annotation">Teilversammlungen der Reichsstände (u.a. Kurfürstentage).</note><orig> /</orig>
<lb/>von einem gemeinen<supplied>,</supplied> beharlichen <choice><orig>vnnd</orig><reg>unnd</reg></choice> <choice><orig>beſtendigen</orig><reg>bestendigen</reg></choice>
<lb/>Frieden<choice><orig> /</orig><reg>,</reg></choice> <choice><orig>zwiſchen</orig><reg>zwischen</reg></choice> des <rs type="place" ref="#heiliges_roemisches_reich">Heyligen Reychs</rs> Stenden<orig> /</orig>
<lb/>der <choice><orig>ſtrittigen</orig><reg>strittigen</reg></choice> Religion halben<orig> /</orig> <choice><orig>auffzůrichten</orig><reg>auffzurichten</reg></choice><choice><orig> /</orig><reg>,</reg></choice> <w>viel
<lb rend="trennstrich"/>faltig</w> gehandlet<choice><orig> /</orig><reg>,</reg></choice> <choice><orig>gerathſchlagt</orig><reg>gerathschlagt</reg></choice><orig> /</orig> <choice><orig>vnd</orig><reg>und</reg></choice> etlich mal <choice><orig><w>Fried
<lb rend="trennstrich"/>ſtende</w></orig><reg><w>Fried<lb rend="trennstrich"/>stende</w></reg></choice><note type="annotation">Frieden.</note> auffgericht <choice><orig>woꝛden</orig><reg>worden</reg></choice><choice><orig>.</orig><reg>,</reg></choice><note type="annotation">Vor dem Augsburger Religionsfrieden wurden mit dem <ref type="quelle" target="nuernberger_anstand.xml">Nürnberger Anstand und Kaiserlichen Mandat (1532)<ref type="print">, oben S. #</ref></ref>, dem <ref type="quelle" target="frankfurter_anstand.xml">Frankfurter Anstand (1539)<ref type="print">, oben S. #</ref></ref>, Speyrer Reichsabschied (1544) und <ref type="quelle" target="passauer_vertrag.xml">Passauer Vertrag (1552)<ref type="print">, oben S. #</ref></ref> bereits Regelungen im <rs type="place" ref="#heiliges_roemisches_reich">Reich</rs> zu einzelnen strittigen Fragen in der Religion erreicht (vgl. <rs type="bibl" ref="#kohnle_nuernberg"><surname type="author">Kohnle</surname>, Nürnberg, S. 5-15</rs>).</note> Welche aber <choice><orig>zůerhaltung</orig><reg>zuerhaltung</reg></choice>
<lb/>des Friedens niemals <choice><orig>genugſam</orig><reg>genugsam</reg></choice> <choice><orig>geweſen</orig><reg>gewesen</reg></choice><choice><orig> /</orig><reg>,</reg></choice> <choice><orig>ſonder</orig><reg>sonder</reg></choice><supplied>,</supplied>
<lb/>deren<orig> /</orig> <choice><orig>vnangeſehen</orig><reg>unangesehen</reg></choice><supplied>,</supplied> die Stende des <rs type="place" ref="#heiliges_roemisches_reich">Reychs</rs><orig> /</orig> für <choice><orig>vnnd</orig><reg>unnd</reg></choice>
<lb/>für<note type="annotation">immerzu.</note> in widerwillen <choice><orig>vnd</orig><reg>und</reg></choice> <choice><orig>mißuertrawen</orig><reg>mißvertrauen</reg></choice> gegen einander
<lb/><choice><orig>ſtehen</orig><reg>stehen</reg></choice> blieben<note type="crit_app"><rs type="bibl" ref="#drta_jr_20_4">DRTA.JR 20,4, S. 3107, Z. 35</rs>: beleiben.</note><choice><orig> /</orig><reg>,</reg></choice> darauß nicht geringer <choice><orig>vnrath</orig><reg>unrath</reg></choice><orig> /</orig> <choice><orig>ſein</orig><reg>sein</reg></choice><note type="crit_app">Fehlt <rs type="bibl" ref="#drta_jr_20_4">DRTA.JR 20,4, S. 3107, Z. 35</rs>.</note> <choice><orig><w>vr
<lb rend="trennstrich"/>ſprung</w></orig><reg><w>ur<lb rend="trennstrich"/>sprung</w></reg></choice> erlanget<choice><orig>.</orig><reg>,</reg></choice> Wo <choice><orig>ferꝛ</orig><reg>ferr</reg></choice><note type="annotation">falls.</note> dann inn werender <w>Spal
<lb rend="trennstrich"/>tung</w> der Religion ein ergentzte Tractation <choice><orig>vnd</orig><reg>und</reg></choice> <w>hand </w></p></div>
</body>
</text>
</TEI>
and I want the <lb/>tags to be counted and displayed inside a html-<span>at the beginning of every n-th line.
Our <lb>-transformations so far:
<xsl:stylesheet xmlns:exist="http://exist.sourceforge.net/NS/exist" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:mets="http://www.loc.gov/METS/" xmlns:rdf="http://www.w3.org/TR/2004/REC-rdf-syntax-grammar-20040210/" xmlns:tei="http://www.tei-c.org/ns/1.0" xmlns:xlink="http://www.w3.org/1999/xlink" exclude-result-prefixes="tei mets xlink exist rdf mods" version="1.0">
<xsl:template match="tei:lb">
<xsl:variable name="myId" select="generate-id()"/>
<xsl:if test="parent::tei:w or #rend='trennstrich'">
<span class="reg">-</span>
<xsl:if test="#rend='trennstrich'">
<span class="orig">-</span>
</xsl:if>
</xsl:if>
<!-- here I tried adding the <xsl:if> -->
<xsl:choose><!-- ancestor:tei:cell hinzugefügt wegen Tabelle, SK 07.06.2019 -->
<xsl:when test="generate-id((ancestor::tei:p[not(descendant::tei:cell)] | ancestor::tei:cell | ancestor::tei:head)//tei:lb[1]) != $myId">
<br/>
</xsl:when> ->
<xsl:when test="ancestor::tei:p/#resp">
<br/>
</xsl:when>
<xsl:otherwise>
<!-- <br/>-->
</xsl:otherwise>
</xsl:choose>
</xsl:template>
I am at the moment unable to integrate what I want to this transformation, thus I have returned once more to the mighty stackoverflow!
If I only run one transformation it works.
namely this one:
<xsl:template match="tei:lb[position() mod 5 = 0]">
<span class="linenumber">
<xsl:number level="any"/>
</span>
<xsl:apply-templates></xsl:apply-templates>
</xsl:template>
How can I integrate this in our template froma bove so that it's working? :-D
I tried unsuccessfully to integrate the <xsl:template> with
<xsl:if test="tei:lb[tei:lb[position() mod 5 = 0]">
<span class="linenumber"><xsl:number level="any"/></span>
</xsl:if>
in the aforementioned XSL, I added a comment at the position!
Can anyone help me?
All the best,
K

Related

XSLT: How to get ancestor-text content

I have the following stylesheet, whcih I created with lots of help from all of you!
<xsl:template match="/">
<xsl:for-each select="$files">
<xsl:result-document href="{substring-before(document-uri(), '.xml')}.txt" method="text">
Kuerzel;AT/NT;Stelle;Zitat
<xsl:apply-templates select="//note"></xsl:apply-templates>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
<xsl:template match="//note">
<xsl:choose>
<xsl:when test="child::*[1][self::ref[#type='biblical']]">
<xsl:for-each select="child::*[#type='biblical']/#cRef">
<xsl:value-of select="."/>
<xsl:text>;</xsl:text>
</xsl:for-each>
<xsl:text></xsl:text>
<xsl:text>test;</xsl:text>
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="ancestor::q[1]"> <!-- this is the part in question -->
<xsl:value-of select="ancestor::q[1]"></xsl:value-of>
<xsl:text>;</xsl:text>
</xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
<xsl:text>
</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:template>
it's supposed to grab the <q> before the <note><ref type="biblical"> in this art of XML:
<text><body>
<div><head facs="#facs_13_TextRegion_1624022854326_321">
<pb facs="#facs_13" xml:id="img_0013" n="4v"/>
<lb facs="#facs_13_line_1624022854428_324" n="N001"/>Von dem Menschen vor dem fall.</head>
<p facs="#facs_13_TextRegion_1624022900738_331">
<lb facs="#facs_13_line_1624022854429_325" n="N001"/>Gott hat von anfang den Menschen erschaffen
<lb facs="#facs_13_r2l4" n="N002"/><note place="margin-left" facs="#facs_13_TextRegion_1624023026742_370">
<lb facs="#facs_13_r1l1" n="N001"/>Gen. 1.</note>zu seinem Ebenbilde und gleichnuß<note type="annotation">Vgl. <ref type="biblical" cRef="Gn_1,26-27">Gen 1,26f.</ref></note> und in mit
<lb facs="#facs_13_r2l5" n="N003"/>gnaden geziert, auch durch die erblich <w>gerechtig<pc>-</pc>
<lb facs="#facs_13_r2l7" n="N004"/>keit</w> dermassen zugerichtet, das er in allen <w>kreff<pc>-</pc>
<lb facs="#facs_13_r2l8" n="N005"/>ten</w> deß leibs und der seelen gantz recht were und von <w>kei<pc>-</pc>
<lb facs="#facs_13_r2l9" n="N006"/>nen</w> bösen unnd unordenlichen bewegungen angefochten
<lb facs="#facs_13_r2l10" n="N007"/>wurde, sonder das inn ime das fleisch dem Geist und die
<lb facs="#facs_13_r2l11" n="N008"/>understen krefften der seele den obersten (welche allein zu
<lb facs="#facs_13_r2l12" n="N009"/>dem guten anweyßten) gehorsam weren.
</p>
<p facs="#facs_13_TextRegion_1624022922087_339">
<lb facs="#facs_13_line_1624022900872_333" n="N001"/>Da nun das<note type="crit_app"><bibl><ref type="bibl" target="#mehlhausen_augsburger_interim"><surname type="editor">Mehlhausen</surname>, Augsburger Interim</ref>, S. 36</bibl>: des.</note> menschen gemüt dermassen wol <w>zuge<pc>-</pc>
<lb facs="#facs_13_r2l14" n="N002"/><note place="margin-left" facs="#facs_13_TextRegion_1624023026742_369">
<lb facs="#facs_13_r1l2" n="N001"/>Eccle. 15.</note>richtet</w> was, <q>hat in Gott gelassen inn der hand seines <w>eig<pc>-</pc>
<lb facs="#facs_13_r2l15" n="N003"/>nen</w> Raths</q><note type="annotation"><ref type="biblical" cRef="Sir_15,14">Sir 15,14</ref>.</note>, Also weyt, das er nicht weniger macht hette
<lb facs="#facs_13_r2l16" n="N004"/>zu wölen das gut als das böse.
</p>
<p facs="#facs_13_TextRegion_1624022943633_345">
<lb facs="#facs_13_r2l17" n="N001"/>Wo sich dann der Mensch diser seiner freiheit recht
<lb facs="#facs_13_r2l18" n="N002"/>gebraucht, auch den gebotten, die ime Gott selbs gegeben,
<lb facs="#facs_13_r2l19" n="N003"/>gehorsam gewesen were, so hette er die güter und <w>gerechtig<pc>-</pc>
<lb facs="#facs_13_r2l20" n="N004"/>keit</w>, die er empfangen, ime selbst und allen seinen <w>nachkom<pc>-</pc>
<lb facs="#facs_13_r2l21" n="N005"/>men</w> erhalten, auch ime und inen nicht gemangelt, <w>frümb<pc>-</pc>
<lb facs="#facs_13_r2l22" n="N006"/>klich</w> und seligklich zuleben. Es het ine auch weder hunger
<lb facs="#facs_13_r2l23" n="N007"/>noch durst, hitz noch kelte, schmertz noch kranckheit noch
<lb facs="#facs_13_r2l24" n="N008"/>der todt betrübt oder geengstiget. Besonder het er alle <w>sün<pc>-</pc>
<lb facs="#facs_13_r2l25" n="N009"/>den</w> und gebrechen gemitten und<note type="crit_app">Fehlt <bibl><ref type="bibl" target="#mehlhausen_augsburger_interim"><surname type="editor">Mehlhausen</surname>, Augsburger Interim</ref>, S. 36</bibl>.</note> von den straffen als <w>be<pc>-</pc>
<lb facs="#facs_13_r2l26" n="N010"/>lonungen</w> der sünden sich keinerley gefahr weder für sich
<lb facs="#facs_13_r2l27" n="N011"/>selbst noch seine nachkommen besorgen dürffen.
</p>
</div>
</body></text>
My expected output is something like this:
Kuerzel;AT/NT;Stelle;Zitat
Gn_1,26-27;test;Vgl. Gen 1,26f.;
Sir_15,14;test;Sir 15,14.;hat Gott gelassen inn der hand seines...
And thus I added the line in question in the template, hoping to resolve this issue that way.
However, It does not seem to work :-/
Alternatively I could probably also look for a substring "Vgl." in the note-element and then go to the <q> directly before.
Can anyone please help me?
There doesn't seem to be any ancestor relation between the q element and the note with ref/#type = 'biblical'.
Perhaps preceding::q[1] is what you are looking for but you make it rather hard for us to help if you don't cut samples to a minimum to demonstrate the issue.

Working with an XSLT barchart

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

closing box is need to apply when this relevant code is missing

I have the input xml as follows. In this xml, sometimes, <par class="endboxa"> is missing. But, anyway i need to match this input and output box equally on the output. I mean whenever, the endboxa is missing, then, anyway, i need to do match this. Any help?
input xml
[code]
<par class="startboxa"><inline style="border-bottom-width: 3.0pt; border-bottom-style: solid; border-bottom-color: #ff0000; list-style-type: decimal; "></inline></par>
<par class="para" xml:lang="de"><inline style="list-style-type: decimal; ">Alle Aspekte der Verfügbarkeit und alle Phasen des Servicelebenszyklus sind bei den Service Design Aktivitäten zu berücksichtigen.</inline></par>
<par class="para" xml:lang="de"><inline style="list-style-type: decimal; ">Der Beitrag des Availability Management zu den Design-Aktivitäten ist:</inline></par>
<par class="para" xml:lang="de"><inline style="list-style-type: decimal; ">Können die Verfügbarkeitsanforderungen nicht eingehalten indem geprüft wird, ob eine entsprechend leistungsfähige Technologie in das vorgeschlagene IT-Design implementiert werden kann. Beispiel:</inline></par>
<par class="startboxa"><inline style="border-bottom-width: 3.0pt; border-bottom-style: solid; border-bottom-color: #ff0000; list-style-type: decimal; "></inline></par>
<par class="para" xml:lang="de"><inline style="list-style-type: decimal; font-weight: bold; ">Hinweise und Tipps</inline></par>
<par class="para" xml:lang="de"><inline style="list-style-type: decimal; ">Dokugen werden und in geeignete Governance-Strukturen integriert werden, die auf die Einführung neuer IT Services ausgerichtet sind.</inline></par>
<par class="endboxa"><inline style="list-style-type: decimal; border-top-width: 3.0pt; border-top-style: solid; border-top-color: #ff0000; "></inline></par>
[/code]
My xslt code as of now, I need to updated based on the advise
<xsl:template match="par[#class = 'startboxa']">
<xsl:text disable-output-escaping="yes"><div class="panel"></xsl:text>
</xsl:template>
<xsl:template match="par[#class = 'endboxa']">
<xsl:text disable-output-escaping="yes"></div></xsl:text>
</xsl:template>
output XML [Now I am getting]
[code]
<div class="panel">
<p class="para">Alle Aspekte der Verfügbarkeit und alle Phasen des Servicelebenszyklus sind bei den Service Design Aktivitäten zu berücksichtigen.</inline></p>
<p class="para">Der Beitrag des Availability Management zu den Design-Aktivitäten ist:</inline></p>
<p class="para">Können die Verfügbarkeitsanforderungen nicht eingehalten indem geprüft wird, ob eine entsprechend leistungsfähige Technologie in das vorgeschlagene IT-Design implementiert werden kann. Beispiel:</inline></p>
<div class="panel">
<p class="para">Hinweise und Tipps</inline></p>
<p class="para">Dokugen werden und in geeignete Governance-Strukturen integriert werden, die auf die Einführung neuer IT Services ausgerichtet sind.</inline></p>
</div>
[/code]
Correct output XML[that i need]
[code]
<div class="panel">
<p class="para">Alle Aspekte der Verfügbarkeit und alle Phasen des Servicelebenszyklus sind bei den Service Design Aktivitäten zu berücksichtigen.</inline></p>
<p class="para">Der Beitrag des Availability Management zu den Design-Aktivitäten ist:</inline></p>
<p class="para">Können die Verfügbarkeitsanforderungen nicht eingehalten indem geprüft wird, ob eine entsprechend leistungsfähige Technologie in das vorgeschlagene IT-Design implementiert werden kann. Beispiel:</inline></p>
</div>[`here i need closing tag`]
<div class="panel">
<p class="para">Hinweise und Tipps</inline></p>
<p class="para">Dokugen werden und in geeignete Governance-Strukturen integriert werden, die auf die Einführung neuer IT Services ausgerichtet sind.</inline></p>
</div>
[/code]
You've tagged this as XSLT 2.0, which is good, as you should be able to use xsl:for-each-group here, to group your par elements, starting with the "startboxa" one
<xsl:for-each-group select="par" group-starting-with="par[#class='startboxa']">
With this approach, you don't actually have to worry about whether the 'endboxa' exists or not. Just output a div and output everything within it
<div>
<xsl:apply-templates select="current-group()" />
</div>
This would pick up the "startboxa", and the "endboxa" (if it is exists), so you just need two matching templates to ignore them (unless you did want to output something different for them)
<xsl:template match="par[#class = 'startboxa']" />
<xsl:template match="par[#class = 'endboxa']" />
Try this XSLT. This assumes your current XML is part of a parent element called parent:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="parent">
<xsl:for-each-group select="par" group-starting-with="par[#class='startboxa']">
<div>
<xsl:apply-templates select="current-group()" />
</div>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="par[#class = 'para']">
<p><xsl:apply-templates /></p>
</xsl:template>
<xsl:template match="par[#class = 'startboxa']" />
<xsl:template match="par[#class = 'endboxa']" />
</xsl:stylesheet>
EDIT: If you did actually wanted an XSLT 1.0 solution, you can replicate the "group-starting-with" by defining a key that groups the par elements by their first most preceding "startboxa" element
<xsl:key name="par" match="par[not(#class='startboxa')]"
use="generate-id(preceding-sibling::par[#class='startboxa'][1])" />
You then change the xsl:for-each-group to just an xsl:for-each to get the 'starting' element
<xsl:for-each select="par[#class='startboxa']">
Then, to get the elements in the group, you can use the key
<xsl:apply-templates select="key('par', generate-id())" />
The main difference is the key does not actually include the 'startboxa' element itself, so you don't need the extra template to ignore it.
Try this XSLT 1.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="par" match="par[not(#class='startboxa')]" use="generate-id(preceding-sibling::par[#class='startboxa'][1])" />
<xsl:template match="parent">
<xsl:for-each select="par[#class='startboxa']">
<div>
<xsl:apply-templates select="key('par', generate-id())" />
</div>
</xsl:for-each>
</xsl:template>
<xsl:template match="par[#class = 'para']">
<p><xsl:apply-templates /></p>
</xsl:template>
<xsl:template match="par[#class = 'endboxa']" />
</xsl:stylesheet>

How to find all numbers in a string

Ich versuche mit einer Funktion sämtliche Zahlen aus einem Element oder String zu ermitteln. Dabei soll die Anzahl der Zahlen und ihre Stelligkeit egal sein.
Folgende Funktion habe ich bislang geschrieben:
<xsl:function name="itp:find_num">
<xsl:param name="tmp"/>
<xsl:if test="matches($tmp,'\d+')">
<xsl:analyze-string select="$tmp" regex="{'\d+'}">
<xsl:matching-substring>
<xsl:sequence select="."/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="''"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:if>
</xsl:function>
Beispiel XML:
<address>street 12, 12345 town<address>
Bei dem Funktionsaufruf soll dann die entsprechende Zahl ausgewählt werden können:
...select="itp:find_num(address)[2]"/>
Zum Beispiel die 2 für die Postleitzahl.
Das Problem ist nun, dass in der Sequence auch leere Werte stehen, so dass ich in der Praxis die Postleitzahl nur mit [4] erreiche.
Gibt es eine elegantere Möglichkeit meine Problem zu lösen?
Und wenn nicht, wie lösche ich die leeren Elemente aus der Sequence??
Now in Englisch :-)
I'm trying to find all numbers in an element oder string. It shouldn't matter how many numbers are available or at which position they are in the string.
Here is my function:
<xsl:function name="itp:find_num">
<xsl:param name="tmp"/>
<xsl:if test="matches($tmp,'\d+')">
<xsl:analyze-string select="$tmp" regex="{'\d+'}">
<xsl:matching-substring>
<xsl:if test=". != ''">
<xsl:sequence select="."/>
</xsl:if>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="''"/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:if>
</xsl:function>
Example XML
<address>street 12, 12345 town<address>
When I call the function I want to choose, which number I want to pick:
...select="itp:find_num(address)[2]"/>
Par example [2] for the postal code.
The Problem I have is, that there are empty elements in the sequence, so that I have to choose [4] to get the postal code.
Is there a easier way to solve my problem?
Or is there a way to remove all empty elements in that sequence??
Thanks :-)
There is no need for complex xsl:analyze-string processing at all.
This XPath one-liner:
for $i in tokenize($pStr, '[^0-9]+')[.]
return xs:integer($i)
produces the wanted sequence of the integers in the string:
12 12345
Here is a complete transformation:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
<xsl:output method="text"/>
<xsl:template match="/*">
<xsl:sequence select="my:nums(.)"/>
</xsl:template>
<xsl:function name="my:nums" as="xs:integer*">
<xsl:param name="pStr" as="xs:string"/>
<xsl:sequence select=
"for $i in tokenize($pStr, '[^0-9]+')[.]
return xs:integer($i)"/>
</xsl:function>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<address>street 12, 12345 town</address>
the wanted, correct result is produced:
12 12345
Even simpler, XPath 3.0 one-liner:
tokenize($pStr, '[^0-9]+')[.] ! xs:integer(.)
I would write the function as
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.org/mf"
exclude-result-prefixes="xs mf">
<xsl:function name="mf:find_num" as="xs:integer*">
<xsl:param name="input" as="xs:string"/>
<xsl:analyze-string select="$input" regex="[0-9]+">
<xsl:matching-substring>
<xsl:sequence select="xs:integer(.)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:function>
<xsl:template match="address">
<xsl:value-of select="mf:find_num(.)" separator=", "/>
</xsl:template>
</xsl:stylesheet>
Of course converting to xs:integer is optional, if you want the function to return a sequence of strings containing digits you would simply change it to do
<xsl:function name="mf:find_num" as="xs:string*">
<xsl:param name="input" as="xs:string"/>
<xsl:analyze-string select="$input" regex="[0-9]+">
<xsl:matching-substring>
<xsl:sequence select="."/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:function>

Grouping *almost* unique ids

I'm struggling with grouping ids that are almost the same. Basically I need to group the content of the PF.A1PF and PersIntr.Personnel.AlPersonnelActive sections and strip the substring before to get my id. I do not have a listing of all the section ids.
Please see below for examples.
Here's the current XML:
<group>
<section id="unique_1_Connect_42_PF.AlPF">
<msgph id="doc" xml:lang="en_US">It has been a external net failure. The pumps are
blocked.</msgph>
<msgph id="cstext" xml:lang="en_US">Mains error</msgph>
<msgph id="localtext" xml:lang="en_US">Mains error</msgph>
</section>
<section id="unique_1_Connect_42_PersIntr.Personnel.AlPersonnelActive">
<msgph id="doc" xml:lang="en_US">Personal alarm warning time has run out without reset.
Personnel in danger !</msgph>
<msgph id="cstext" xml:lang="en_US">Personal alarm</msgph>
<msgph id="localtext" xml:lang="en_US">Pers. alarm</msgph>
</section>
<section id="unique_2_Connect_42_PF.AlPF">
<msgph id="doc" xml:lang="es_ES">Ha habido un fallo de red externa. Las bombas están
bloquedas.</msgph>
<msgph id="cstext" xml:lang="es_ES">Fallo energía de entrada</msgph>
<msgph id="localtext" xml:lang="es_ES">Fallo energía</msgph>
</section>
<section id="unique_2_Connect_42_PersIntr.Personnel.AlPersonnelActive">
<msgph id="doc" xml:lang="es_ES">Tiempo de espera de la alarma de personal ha finalizado sin
reseteo. ¡Personal en peligro!</msgph>
<msgph id="cstext" xml:lang="es_ES">Alarma personal</msgph>
<msgph id="localtext" xml:lang="es_ES">Alarma personal</msgph>
</section>
Here's what I need to output:
<Rsc Id="PF.AlPF">
<Documentation en_US="It has been a external net failure. The pumps are blocked."
es_ES="Ha habido un fallo de red externa. Las bombas están bloquedas."/>
<CSText en_US="Mains error" es_ES="Fallo energía de entrada"/>
<LocalText en_US="Mains error" es_ES="Fallo energía"/>
</Rsc>
<Rsc Id="PersIntr.Personnel.AlPersonnelActive">
<Documentation
en_US="Personal alarm warning time has run out without reset. Personnel in danger !"
es_ES="Tiempo de espera de la alarma de personal ha finalizado sin reseteo. ¡Personal en peligro!"/>
<CSText en_US="Personal alarm" es_ES="Alarma personal"/>
<LocalText en_US="Pers. alarm" es_ES="Alarma personal"/>
</Rsc>
I really appreciate any insight. Thanks in advance for your attention.
Kind regards,
Anne
Update:
Thanks so much, #Dimitre, #Michael. I really appreciate your help with this challenge. I had a little trouble with the element resolving in this portion of the 2.0 solution:
<xsl:element name="{$vNewNames[starts-with(lower-case(.),current()/#id)]}">
<xsl:for-each select="current-group()">
<xsl:attribute name="{#xml:lang}" select="."/>
</xsl:for-each>
</xsl:element>
Here's what finally worked:
<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="/*">
<Resources>
<Type key="Alarm">
<xsl:for-each-group select="//section" group-by="substring-after(#id, '_42_')">
<xsl:variable name="currentID" select="substring-after(#id, '_42_')"/>
<xsl:element name="Rsc">
<xsl:attribute name="id" select="$currentID"/>
<xsl:for-each-group select="//section[$currentID]/msgph"
group-by="substring-after(#id, '_42_')">
<xsl:choose>
<xsl:when test="substring-after(#id, '_42_')='doc'">
<Documentation>
<xsl:for-each select="current-group()">
<xsl:if test="contains(parent::*/#id,$currentID)">
<xsl:attribute name="{#xml:lang}" select="."/>
</xsl:if>
</xsl:for-each>
</Documentation>
</xsl:when>
<xsl:when test="substring-after(#id, '_42_')='cstext'">
<CSText>
<xsl:for-each select="current-group()">
<xsl:if test="contains(parent::*/#id,$currentID)">
<xsl:attribute name="{#xml:lang}" select="."/>
</xsl:if>
</xsl:for-each>
</CSText>
</xsl:when>
<xsl:when test="substring-after(#id, '_42_')='localtext'">
<LocalText>
<xsl:for-each select="current-group()">
<xsl:if test="contains(parent::*/#id,$currentID)">
<xsl:attribute name="{#xml:lang}" select="."/>
</xsl:if>
</xsl:for-each>
</LocalText>
</xsl:when>
</xsl:choose>
</xsl:for-each-group>
</xsl:element>
</xsl:for-each-group>
</Type>
</Resources>
</xsl:template>
Thanks again!
Anne
This transformation:
<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="ksectById" match="section"
use="substring-after(#id, '42_')"/>
<xsl:template match=
"section[generate-id()
=
generate-id(key('ksectById',
substring-after(#id, '42_')
)[1]
)
]
">
<xsl:variable name="vId" select=
"substring-after(#id, '42_')"/>
<xsl:variable name="vGroup" select=
"key('ksectById',$vId)"/>
<Rsc Id="{$vId}">
<Documentation>
<xsl:apply-templates select=
"$vGroup/msgph[#id='doc']/#xml:lang"/>
</Documentation>
<CSText>
<xsl:apply-templates select=
"$vGroup/msgph[#id='cstext']/#xml:lang"/>
</CSText>
<LocalText>
<xsl:apply-templates select=
"$vGroup/msgph[#id='localtext']/#xml:lang"/>
</LocalText>
</Rsc>
</xsl:template>
<xsl:template match="#xml:lang">
<xsl:attribute name="{.}">
<xsl:value-of select=".."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="*/*" priority="-1"/>
</xsl:stylesheet>
when applied on the provided XML document:
<group>
<section id="unique_1_Connect_42_PF.AlPF">
<msgph id="doc" xml:lang="en_US">It has been a external net failure. The pumps are blocked.</msgph>
<msgph id="cstext" xml:lang="en_US">Mains error</msgph>
<msgph id="localtext" xml:lang="en_US">Mains error</msgph>
</section>
<section id="unique_1_Connect_42_PersIntr.Personnel.AlPersonnelActive">
<msgph id="doc" xml:lang="en_US">Personal alarm warning time has run out without reset. Personnel in danger !</msgph>
<msgph id="cstext" xml:lang="en_US">Personal alarm</msgph>
<msgph id="localtext" xml:lang="en_US">Pers. alarm</msgph>
</section>
<section id="unique_2_Connect_42_PF.AlPF">
<msgph id="doc" xml:lang="es_ES">Ha habido un fallo de red externa. Las bombas están bloquedas.</msgph>
<msgph id="cstext" xml:lang="es_ES">Fallo energía de entrada</msgph>
<msgph id="localtext" xml:lang="es_ES">Fallo energía</msgph>
</section>
<section id="unique_2_Connect_42_PersIntr.Personnel.AlPersonnelActive">
<msgph id="doc" xml:lang="es_ES">Tiempo de espera de la alarma de personal ha finalizado sin reseteo. ¡Personal en peligro!</msgph>
<msgph id="cstext" xml:lang="es_ES">Alarma personal</msgph>
<msgph id="localtext" xml:lang="es_ES">Alarma personal</msgph>
</section>
</group>
produces exactly the wanted, correct result:
<Rsc Id="PF.AlPF">
<Documentation en_US="It has been a external net failure. The pumps are blocked." es_ES="Ha habido un fallo de red externa. Las bombas están bloquedas."/>
<CSText en_US="Mains error" es_ES="Fallo energía de entrada"/>
<LocalText en_US="Mains error" es_ES="Fallo energía"/>
</Rsc>
<Rsc Id="PersIntr.Personnel.AlPersonnelActive">
<Documentation en_US="Personal alarm warning time has run out without reset. Personnel in danger !" es_ES="Tiempo de espera de la alarma de personal ha finalizado sin reseteo. ¡Personal en peligro!"/>
<CSText en_US="Personal alarm" es_ES="Alarma personal"/>
<LocalText en_US="Pers. alarm" es_ES="Alarma personal"/>
</Rsc>
Explanation: Muenchian grouping with key that is defined as a substring of the id attribute.
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:variable name="vNewNames" select=
"'Documentation', 'CSText', 'LocalText'"/>
<xsl:template match="/*">
<xsl:for-each-group select="section"
group-by="substring-after(#id, '_42_')">
<xsl:variable name="vId" select=
"substring-after(#id, '42_')"/>
<Rsc Id="{$vId}">
<xsl:for-each-group select="current-group()/*"
group-by="#id">
<xsl:element name=
"{$vNewNames[starts-with(lower-case(.),current()/#id)]}">
<xsl:for-each select="current-group()">
<xsl:attribute name="{#xml:lang}" select="."/>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</Rsc>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
This code uses some very powerful and most natural XSLT 2.0 features, such as <xsl:for-eac-group>, current-group(), sequences, the select attribute of <xsl:attribute>. The result is almost twice shorter code that is much more readable and maintainable.
I don't know a considerable amount about XSLT, but it seems like you should be able to use the XSLT substring function to strip out the first 22 characters of each section[id] and return the significant portion.
Define "almost". Only then you'll be able to come up with a reasonable solution. Most likely you will then solve it yourself with basic xslt functions.