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>
Related
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.
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
Essentially, I'm struggling with the same XSLT problem as another questioner asking on this site, namely the user "bigsky" in a post of 2013 (s. Trim white-spaces at the end of lines only before a specific tag). But in spite of a useful hint (in the answer of Sperberg-McQueen), I couldn't figure out a satisfying solution for the issue.
What I'm trying to do is, transforming an XML file into a readable HTML document, to create a running "body" text and recombine at line breaks the strings of words divided, that is interrupted by an <lb break="no"/> element, in my original document - but recombine them without whitespaces!
Having played around with several templates in my XSLT stylesheet, I defined one - following the hint of the post mentioned above - to process all nodes preceding a <lb break="no"/> element, and I tried to remove their leading and trailing whitespaces making use of the normalize-space() function, so that the strings preceding and following the specified <lb> nodes should be concatenated in the output.
Now, for the most part of the cases, I've actually got the output I desired - however, in some places appears (to my surprise) whitespace before the re-concatenated string, which has no counterpart in my XML file and which I would like to get rid of.
As the relevant files deal with a document of a certain length, I'll show you only extracts of the code - but I'll include parts where the transformation works as wanted, as well as parts where the transformation produces unexpected whitespace.
Concerning the text document at issue, just a brief note for your information: The XML file covers the text of a medieval Latin manuscript according to conventions of the Text Encoding Initiative (TEI) and is, among other things, intended to record palaeographic features of the manuscript (- in case you wonder about the tags/elements I've used). Actually, I'd like to ask you to have a look primarily at the sections around the <lb break="no"/> elements and ignore the details of my text encoding - but at the same time I wanted to show you the selected passages as they appear in my edition (not least because I'm unsure as to the role of adjacent elements ...).
--> Extract from the XML file:
<?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>Gesta Francorum et aliorum Hierosolimitanorum</title>
<!-- some code -->
</titleStmt>
<publicationStmt>
<publisher></publisher>
</publicationStmt>
<sourceDesc>
<msDesc xml:lang="en">
<msIdentifier>
<settlement>Vatican City (Rome)</settlement>
<repository key="https://www.vaticanlibrary.va">Biblioteca Apostolica Vaticana</repository>
<idno type="shelfmark">Reg. lat. 572</idno>
<msName>Codex Vaticanus Reginensis latinus 572</msName>
</msIdentifier>
<!-- some code -->
</msDesc>
</sourceDesc>
</fileDesc>
<!-- some code -->
</teiHeader>
<text>
<body>
<div type="text" subtype="book" n="1">
<ab>
<!-- FIRST PASSAGE -->
<pb n="1v"/>
<!-- some code -->
<lb n="21"/>... <hi rend="colour:red">A</hi>it
<lb n="22"/><expan>na<am><g ref="#macron"/></am><ex>m</ex><am><g ref="#abbr_que"/></am><ex>que</ex></expan> <rs type="person" ref="http://d-nb.info/gnd/118763873"><expan>domn<am><g ref="#abbr_us"/></am><ex>us</ex></expan> <expan>ap<ex>osto</ex>l<am><g ref="#macron"/></am>icus</expan></rs>: <said aloud="true"><hi rend="colour:red">F</hi>ratres, uos
<pb n="2r"/>
<lb n="1"/>oportet multa pati <expan><am><g ref="#p_flourish"/></am><ex>pro</ex></expan> nomine <choice><orig><expan><am>xp<g ref="#macron"/></am><ex>christ</ex>i</expan></orig><reg>Christi</reg></choice>, ui
<lb n="2" break="no"/>delicet miserias, <expan>pau<am><g ref="#p_stroke"/></am><ex>per</ex>tates</expan>, nuditates,
<lb n="3"/><expan><am><g ref="#p_stroke"/></am><ex>per</ex>secutiones</expan>, egestates, infirmitates,
<lb n="4"/>fames, sites, <expan><am>&</am><ex>et</ex></expan> alia huiusmodi ... </said>
<!-- SECOND PASSAGE -->
<!-- some code -->
<pb n="3r"/>
<lb n="13" rend="text-indent -1em"/><hi rend="colour:red">A</hi>nte <expan>porta<am><g ref="#macron"/></am><ex>m</ex></expan> castri erat puteus, <expan><am>&</am><ex>et</ex></expan> ad <expan>pede<am><g ref="#macron"/></am><ex>m</ex></expan>
<lb n="14"/>castri fons uiuus, iuxta <expan>que<am><g ref="#macron"/></am><ex>m</ex></expan> exiit <persName><expan>Rai
<lb n="15" break="no"/>nald<am><g ref="#abbr_us"/></am><ex>us</ex></expan></persName> insidiari <orgName type="ethnic"><choice><orig>turcos</orig><reg>Turcos</reg></choice></orgName>. <hi rend="colour:red">V</hi>enientes <expan>u<am><g ref="#o_superscript"/></am><ex>ero</ex></expan>
<lb n="16"/><orgName type="ethnic"><choice><orig>turci</orig><reg>Turci</reg></choice></orgName> <date when="1096-09-20" type="occasion">in festo sancti <expan>Michahel<ex>is</ex></expan></date>, inuener<ex>un</ex>t
<lb n="17"/><persName><expan>Rainaldu<am><g ref="#macron"/></am><ex>m</ex></expan></persName> <expan><am>&</am><ex>et</ex></expan> <expan>q<am><g ref="#i_superscript"/></am><ex>ui</ex></expan> <expan>cu<am><g ref="#macron"/></am><ex>m</ex></expan> eo erant, <expan>occider<ex>un</ex>t<am><g ref="#macron"/></am><am><g ref="#abbr_que"/></am><ex>que</ex></expan>
<lb n="18"/><orgName type="ethnic"><choice><orig>turci</orig><reg>Turci</reg></choice></orgName> multos ex eis. <hi rend="colour:red">A</hi>lii fugerunt in
<lb n="19"/><expan>castru<am><g ref="#macron"/></am><ex>m</ex></expan>. <hi rend="colour:red">Q</hi>uod <expan>c<am><g ref="#macron"/></am><ex>on</ex>festi<am><g ref="#macron"/></am><ex>m</ex></expan> <orgName type="ethnic"><choice><orig>turci</orig><reg>Turci</reg></choice></orgName> <expan>obseder<ex>un</ex>t<am><g ref="#macron"/></am></expan>,
<lb n="20"/><expan>eis<am><g ref="#abbr_que"/></am><ex>que</ex></expan> <expan>aqua<am><g ref="#macron"/></am><ex>m</ex></expan> <expan>abstuler<ex>un</ex>t<am><g ref="#macron"/></am></expan>. <hi rend="colour:red">F</hi>ueruntque nostri
<lb n="21"/>in tanta afflictione sitis, ut fleboto
<lb n="22" break="no"/>marent suos <expan>eq<am><g ref="#o_superscript"/></am><ex>uo</ex>s</expan> <expan><am>&</am><ex>et</ex></expan> asinos, <expan>quo<am><g ref="#abbr_rum"/></am><ex>rum</ex></expan> <expan>sangui<add place="below">ne<am><g ref="#macron"/></am><ex>m</ex></add></expan>
<pb n="3v"/>
<lb n="1"/>bibebant. <hi rend="colour:red">A</hi>lii mittebant zonas <expan>at<am><g ref="#abbr_que"/></am><ex>que</ex></expan>
<lb n="2"/>panniculos in <expan>piscina<am><g ref="#macron"/></am><ex>m</ex></expan>, <expan><am>&</am><ex>et</ex></expan> inde <expan>exp<am><g ref="#i_superscript"/></am><ex>ri</ex>meba<hi rend="ligature">nt</hi></expan>
<lb n="3"/><expan>aqua<am><g ref="#macron"/></am><ex>m</ex></expan> in os <expan>suu<am><g ref="#macron"/></am><ex>m</ex></expan>. <hi rend="colour:red">A</hi>lii mingebant <choice><orig>iN</orig><reg>in</reg></choice>
<lb n="4"/>pugillo alterius, <expan><am>&</am><ex>et</ex></expan> bibebant. <hi rend="colour:red">A</hi>lii fodi
<lb n="5" break="no"/>ebant <expan>humida<am><g ref="#macron"/></am><ex>m</ex></expan> <expan>t<am><g ref="#macron"/></am><ex>e</ex>r<ex>r</ex>a<am><g ref="#macron"/></am><ex>m</ex></expan> ...
<!-- some code -->
<!-- THIRD PASSAGE -->
<pb n="7v"/>
<!-- some code -->
<lb n="9"/>... <hi rend="colour:red">Q</hi>ui <expan>resp<am><g ref="#macron"/></am><ex>on</ex>der<ex>un</ex>t<am><g ref="#macron"/></am></expan>:
<lb n="10" rend="text-indent -1em"/><said aloud="true"><hi rend="colour:red">N</hi>os <expan>neq<am><g ref="#i_superscript"/></am><ex>ui</ex>m<am><g ref="#abbr_us"/></am><ex>us</ex></expan> aliud agere. <hi rend="colour:red">I</hi>n roga <rs type="person" ref="http://d-nb.info/gnd/118501925"><expan>im<am><g ref="#p_stroke"/></am><ex>per</ex>a
<lb n="11" break="no"/>toris</expan></rs> locati <expan>sum<am><g ref="#abbr_us"/></am><ex>us</ex></expan>, <expan><am>&</am><ex>et</ex></expan> <expan>q<am><g ref="#i_superscript"/></am><ex>ui</ex>cq<am><g ref="#i_superscript"/></am><ex>ui</ex>d</expan> <expan>nob<am><g ref="#macron"/></am><ex>is</ex></expan> imperat
<lb n="12"/>nos oportet implere.</said>
<!-- some code -->
</ab>
</div>
</body>
</text>
</TEI>
--> Extract from the XSLT file:
<?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"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.tei-c.org/ns/1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="html" encoding="UTF-8"/>
<xsl:template match="TEI/text/body/div/ab">
<!-- <xsl:value-of select="."/> -->
<xsl:apply-templates/>
</xsl:template>
<!-- HERE IS THE TEMPLATE DEALING WITH <LB>-NODES (!) -->
<xsl:template match="text()[following-sibling::*[1][self::lb[#break='no']]]">
<seg style="color:green"><xsl:value-of select="normalize-space()" /></seg>
</xsl:template>
<xsl:template match="TEI/text/body/div/ab/descendant-or-self::hi[#rend='colour:red']">
<seg style="color:darkred; font-weight:bold"><xsl:value-of select="."/></seg>
</xsl:template>
<xsl:template match="TEI/text/body/div/ab/descendant-or-self::hi[#rend='capitalize colour:red']">
<seg style="color:darkred; font-weight:bold"><xsl:value-of select="."/></seg>
</xsl:template>
<xsl:template match="TEI/text/body/div/ab/descendant-or-self::orig"/>
<xsl:template match="TEI/text/body/div/ab/descendant-or-self::am"/>
<!-- MAIN TEMPLATE: HTML output -->
<xsl:template match="/">
<html>
<head>
<title>
Gesta Francorum 1 (XSLT / test)
</title>
<style>
#font-face {
font-family: "Palemonas MUFI";
src: local("Palemonas MUFI Standard") url("file:///C:/Windows/Fonts/PalemMUFI-reg.ttf") format("truetype");
}
/* some code */
</style>
</head>
<body>
<div id="header">
<h1>
<xsl:value-of select="TEI/teiHeader/fileDesc/titleStmt/title"/>
</h1>
<!-- some code -->
</div>
<div id="main_content">
<div id="main_content_text">
<xsl:apply-templates select="TEI/text/body/div/ab"/>
</div>
</div>
<!-- some code -->
</body>
</html>
</xsl:template>
</xsl:stylesheet>
If you have a look at the HTML output, you will see that there is something going wrong (I was able to reproduce the problem with these extracts):
-- In the FIRST PASSAGE I get "Christi , videlicet miserias", instead of the expected "Christi, videlicet miserias" - note the additional whitespace before the first string of the concatenation, that is not in the XML file!
-- In the SECOND PASSAGE I get, as desired, "Rainaldus" and "in tanta afflictione sitis, ut flebotomarent", but at the end unfortunately "A lii fodiebant" instead of "Alii fodiebant" - again, with an additional whitespace before the first string of the concatenation.
-- In the THIRD PASSAGE I get "in roga imper atoris" instead of the expected "in roga imperatoris" - for a third time, with an additional whitespace before the first string of the concatenation.
Can somebody tell me if I am overlooking relevant details concerning the normalize-space() function or one of the XML tags, or have you got a clue where the unwanted whitespace comes from (- again, in the majority of cases my simple solution seems to work)?
Any help from the XSLT experts out there would be appreciated.
(JTLYK: I use the Oxygen XML Editor 21.1 for creating the XML and XSLT files, my browser is Mozilla Firefox 81.0)
=====================================
UPDATE:
Thanks to a suggestion by Martin Honnen (s. his answer below), I think I was able to produce a "quick & dirty" solution for the issue. Using a revised <xsl:output> declaration (as suggested by Honnen = <xsl:output method="html" indent="no" encoding="UTF-8" version="5"/>), the whitespaces that in my output preceded the <seg> elements of the <lb break="no"/> templates, could easily be removed.
Now, I had the problem in some other places of my document that a concatenated string around a <lb break="no"/> element was also linked without dividing whitespace to the preceding element (= due to my normalize-space() command). I solved it simply by shifting such whitespace, where needed, into the preceding element.
Just a very short example of my TEI/XML file:
Instead of
<lb n="4"/><expan>specialit<am><g ref="macron"/></am><ex>er</ex></expan> in euan
<lb n="5" break="no"/>gelio dicens ...
I wrote:
<lb n="4"/><expan>specialit<am><g ref="macron"/></am><ex>er</ex> </expan>in euan
<lb n="5" break="no"/>gelio dicens ...
Output:
Instead of "specialiterin euangelio dicens" for the first snippet, now "specialiter in euangelio dicens", as is desired ...
To be honest, I'm still in doubt whether this is "good" encoding style ...
(What about a solution with the XSLT function ends-with(), as Sperberg-McQueen had in mind answering the 2013 post? Or perhaps a solution with concatenate()? I still have to figure that out ...)
I would try with <xsl:output method="html" indent="no" encoding="UTF-8" version="5"/> or perhaps make sure you use a well defined inline element like span instead of seg.
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>
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.