Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
How to move p & imag element move into the observ element?
Input XML:
<root>
<num>6</num>
<imag>
<apimag fic="[PHOTO]" scale="40"/>
</imag>
<qual>professeur a l'universit</qual>
<h1>Contentieux sur la validité du brevet</h1>
<pnchr><observ/></pnchr>
<p>Selon 1</p>
<h2>Dalai de restauration</h2>
<pnchr><observ/></pnchr>
<p>Selon 2</p>
<imag>
<apimag fic="[PHOTO]" scale="40"/>
</imag>
<pnchr><observ/></pnchr>
<p>Selon 3</p>
<p>Selon 4</p>
</root>
Expected Output:
<root>
<num>6</num>
<imag>
<apimag fic="[PHOTO]" scale="40"/>
</imag>
<qual>professeur a l'universit</qual>
<h1>Contentieux sur la validité du brevet</h1>
<pnchr><observ>
<p>Selon 1</p>
</observ></pnchr>
<h2>Dalai de restauration</h2>
<pnchr><observ>
<p>Selon 2</p>
<imag>
<apimag fic="[PHOTO]" scale="40"/>
</imag>
</observ></pnchr>
<pnchr><observ>
<p>Selon 3</p>
<p>Selon 4</p>
</observ></pnchr>
</root>
Something like this:
<xsl:template match="root">
<xsl:for-each-group select="*" group-starting-with="pnchr">
<xsl:choose>
<xsl:when test="self::pnchr">
<pnchr><observ>
<xsl:copy-of select="remove(current-group(),1)"/>
</observ></pnchr>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:template>
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a xml like this,
<doc>
<para>A brief 23 spell$of hea#vy rain$forc^%ed an early+ lunch$98#with nine</para>
</doc>
I need to break the text string from each $ present in the text.
SO expected output should be,
<doc>
<para>A brief 23 spell</para>
<para>of hea#vy rain</para>
<para>forc^%ed an early+ lunch</para>
<para>98#with nine</para>
</doc>
Can anyone suggest to me how can I do this using XSLT 1.0?
Try this
<xsl:template match="para">
<xsl:call-template name="spilit">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="spilit">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '$')">
<para><xsl:value-of select="substring-before($text, '$')"/></para>
<xsl:call-template name="spilit">
<xsl:with-param name="text" select="substring-after($text, '$')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<para><xsl:value-of select="$text"/></para>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
See Transformation at https://xsltfiddle.liberty-development.net/bEJbVrg
I'm writing an XSLT in which I need to see if a value is in preprocessing instruction. In my XML, the preprocessing looks like below.
<?xpp MAIN;1;1;0;0;69;0;0?>
Sample XML
<root>
<?xpp MAIN;1;0;0;0;73;0;0?>
<preface role="guideline">
<title>title</title>
<section role="group">
<para>data</para>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Licences</title>
<itemizedlist mark="bullet">
<listitem>
<para>itemdata</para>
</listitem>
</itemizedlist>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Letters to the Editor</title>
<itemizedlist mark="bullet">
<listitem>
<para><?xpp MAIN;1;0;0;0;74;0;0?>item data</para>
</listitem>
</itemizedlist>
</section>
</preface>
</root>
Sample1 XML
<root>
<?xpp MAIN;1;0;0;0;83;0;0?>
<preface role="guideline">
<title>title</title>
<section role="group">
<para>data</para>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Licences</title>
<itemizedlist mark="bullet">
<listitem>
<para>itemdata</para>
</listitem>
</itemizedlist>
</section>
<section role="group">
<title>
<?xpp lp;0.5p?>Letters to the Editor</title>
<itemizedlist mark="bullet">
<listitem>
<para><?xpp MAIN;1;0;0;0;84;0;0?>item data</para>
</listitem>
</itemizedlist>
</section>
</preface>
</root>
For the below XML, I need to do the task of going through files and checking for the data. The Above sample XML and Sample1 XML are the files that I've loop through.
<root>
<table frame="none" tabstyle="wrap4">
<tgroup cols="4">
<colspec colnum="1" colname="col1" colwidth="10*"/>
<colspec colnum="2" colname="COLSPEC0" colwidth="10.00*"/>
<colspec colnum="3" colname="col2" colwidth="275*"/>
<colspec colnum="4" colname="col3" colwidth="15*"/>
<tbody>
<row>
<entry colsep="0" rowsep="0">Text1</entry>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0" align="right">75</entry>
</row>
<row>
<entry colsep="0" rowsep="0">Text2</entry>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0"/>
<entry colsep="0" rowsep="0" align="right">84</entry>
</row>
</tbody>
</tgroup>
</table>
</root>
Here first I'm trying to loop through all the files available, in each file, look for the preprocessing containing MAIN in it and then see if my value is present in that preprocessing instruction. Below is my XSLT block.
<xsl:template match="entry[#align='right']" mode="y">
<xsl:analyze-string select="." regex="([0-9]+)">
<xsl:matching-substring>
<xsl:variable name="prent" select="document(document('file:///C:\Users\userId\Desktop\Proview\AUS Journal\02FEB/title.xml')/entry/file/#name)/*[contains(//root/processing-instruction('xpp')[contains(.,'MAIN')],regex-group(1))]/substring-before(tokenize(document-uri(/), '/')[last()], '.')"/>
<xsl:variable name="cha">
<xsl:value-of select="$prent"/>
</xsl:variable>
<xsl:variable name="size">
<xsl:value-of select="string-length($cha)"/>
</xsl:variable>
<xsl:variable name="conct">
<xsl:value-of select="concat($cha,'/pg_',.)"/>
</xsl:variable>
<a href="{$conct}">
<xsl:value-of select="regex-group(1)"/>
</a>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
When I run this I get the below error.
XSLT 2.0 Debugging Error: Error: file:///C:/Users/userId/Desktop/Proview/AUS%20Journal/02FEB/XSLT/Journal.xsl:674: Wrong occurrence to match required sequence type - Details: - XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one').
please let me know how can I fix this and get job done.
Thanks
Try whether changing the step
*[contains(//root/processing-instruction('xpp')[contains(.,'MAIN')],regex-group(1))]
to
*[//root/processing-instruction('xpp')[contains(.,'MAIN')][contains(., regex-group(1))]]
fixes the problem.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
XML file as input and expected output shown below. Can refere link...
XSLT node value comparision
I am looking for output in xml but it would be great if anyone make xslt file which gives/shows result in tabular format.
Desc: XML file contains collection of operatorstation nodes, with each operator station has multiple networks, now collect IP address from each node of every operatorstation and show its value and compared status with every Operator station as shown below. If every operatorstation network IP is equal then it shows status as Equal otherwise Unequal. Comparison should be done with IPAddress with taking reference of Family and Name. Like compare IPAddress of OS01 with other OSs having same family (NetworkSettings) and Name (Network A).
XML file as input
![<?xml version="1.0" encoding="utf-8"?>
<OperatorStationCollection xmlns="http://www.w3.org" >
<OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>KM-OS001</Name>
<Nodes>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network A</Name>
<IPAddress>111.11.11.1</IPAddress>
</DataNodeBase>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network B</Name>
<IPAddress>111.22.11.1</IPAddress>
</DataNodeBase>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network C</Name>
<IPAddress>111.33.11.1</IPAddress>
</DataNodeBase>
</Nodes>
</OperatorStation>
<OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>KM-OS002</Name>
<Nodes>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network A</Name>
<IPAddress>111.11.11.1</IPAddress>
</DataNodeBase>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network B</Name>
<IPAddress>111.22.11.2</IPAddress>
</DataNodeBase>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network D</Name>
<IPAddress>111.33.11.2</IPAddress>
</DataNodeBase>
</Nodes>
</OperatorStation>
<OperatorStation xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>KM-OS003</Name>
<Nodes>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network A</Name>
<IPAddress>111.11.11.1</IPAddress>
</DataNodeBase>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network B</Name>
<IPAddress>111.22.11.3</IPAddress>
</DataNodeBase>
<DataNodeBase xsi:type="Adaptor">
<Family>NetworkSettings</Family>
<Name>Network E</Name>
<IPAddress>111.33.11.3</IPAddress>
</DataNodeBase>
</Nodes>
</OperatorStation>
</OperatorStationCollection>
Expected output.
Expected output using XSLT:
Here no option to add table so please consider <> as separator which is used to design table, <> is not part of result it is just added to separate column values. Please consider below result as it is in table.
Header Name<>Status<>OS01<>OS02<>OS03
Network A<>Equal<>111.11.11.1<>111.11.11.1<>111.11.11.1
Network B<>Unequal<>111.22.11.1<>111.22.11.2<>111.22.11.2
Network C<>Unequal<>111.33.11.1<>Not Exist<>Not Exist
Network D<>Unequal<>Not Exist<>111.33.11.2<>Not Exist
Network E<>Unequal<>Not Exist<>Not Exist<>111.33.11.3
OR Code below shows expected result in tabular format.
Save below code fileName.html.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<table>
<tr>
<td>Name</td><td>Status</td><td>OS01</td><td>OS02</td><td>OS03</td>
</tr>
<tr>
<td>Network A</td><td>Equal</td><td>111.11.11.1</td><td>111.11.11.1</td><td>111.11.11.1</td>
</tr>
<tr>
<td>Network B</td><td>Unequal</td><td>111.22.11.1</td><td>111.22.11.2</td><td>111.22.11.2</td>
</tr>
<tr>
<td>Network C</td><td>Unequal</td><td>111.33.11.1</td><td>Not Exist</td><td>Not Exist</td>
</tr>
<tr>
<td>Network D</td><td>Unequal</td><td>Not Exist</td><td>111.33.11.2</td><td>Not Exist</td>
</tr>
<tr>
<td>Network E</td><td>Unequal</td><td>Not Exist</td><td>Not Exist</td><td>111.33.11.3</td>
</tr>
</table>
</body>
</html>
So you want one column per operator station name, and one row per distinct network name. In XSLT 2.0 this can be done nicely using for-each-group
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:w3="http://www.w3.org" exclude-result-prefixes="w3">
<xsl:template match="/">
<xsl:variable name="allStations"
select="/w3:OperatorStationCollection/w3:OperatorStation" />
<table>
<!-- Header row - two fixed columns plus one per station name -->
<tr>
<td>Name</td><td>Status</td>
<xsl:for-each select="$allStations">
<td><xsl:value-of select="w3:Name" /></td>
</xsl:for-each>
</tr>
<!-- main rows - one per "group" of DataNodeBase elements which share the
same Name -->
<xsl:for-each-group
select="$allStations/w3:Nodes/w3:DataNodeBase"
group-by="w3:Name">
<!-- calculate the column values - the IPAddress if this network (i.e. the
current-group) has an entry for this station, and "None" if not -->
<xsl:variable name="addresses"
select="for $s in ($allStations)
return (current-group()[../.. is $s]/w3:IPAddress, 'None')[1]" />
<tr>
<td><xsl:value-of select="current-grouping-key()" /></td>
<td>
<!-- equal if all the $addresses are the same, unequal otherwise -->
<xsl:value-of select="if (count(distinct-values($addresses)) = 1)
then 'Equal' else 'Unequal'" />
</td>
<xsl:for-each select="$addresses">
<td><xsl:value-of select="."/></td>
</xsl:for-each>
</tr>
</xsl:for-each-group>
</table>
</xsl:template>
</xsl:stylesheet>
If you're limited to 1.0 then the logic is the same but the stylesheet is much more verbose - you'll have to use the "Muenchian grouping" method to replace for-each-group, and the equal/unequal calculation is a bit messier because you don't have the distinct-values function or the capability to define arbitrary sequences of values (the $addresses variable in the 2.0 version):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:w3="http://www.w3.org" exclude-result-prefixes="w3">
<!-- grouping key to pull out all the DataNodeBase elements with a
particular name -->
<xsl:key name="dnbByName" match="w3:DataNodeBase" use="w3:Name" />
<xsl:template match="/">
<xsl:variable name="allStations"
select="/w3:OperatorStationCollection/w3:OperatorStation" />
<table>
<tr>
<td>Name</td><td>Status</td>
<xsl:for-each select="$allStations">
<td><xsl:value-of select="w3:Name" /></td>
</xsl:for-each>
</tr>
<!-- Muenchian grouping - for-each over a set consisting of just one
DataNodeBase per network name "group" -->
<xsl:for-each select="$allStations/w3:Nodes/w3:DataNodeBase[
generate-id() = generate-id(key('dnbByName', w3:Name)[1])]">
<xsl:variable name="current-group" select="key('dnbByName', w3:Name)" />
<xsl:variable name="current-grouping-key" select="w3:Name" />
<tr>
<td><xsl:value-of select="$current-grouping-key" /></td>
<td>
<xsl:choose>
<!-- "Equal" if all stations have a value for this network name,
and all these values are the same (it is not the case that
any of the values is different from that of the first
station) -->
<xsl:when test="count($current-group) = count($allStations)
and not($current-group/w3:IPAddress
!= $current-group[1]/w3:IPAddress)">
<xsl:text>Equal</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Unequal</xsl:text>
</xsl:otherwise>
</xsl:choose>
</td>
<!-- remaining columns, one per station -->
<xsl:for-each select="$allStations">
<td>
<!-- check whether this station has an address for this network -->
<xsl:variable name="address" select="w3:Nodes/w3:DataNodeBase[
w3:Name = $current-grouping-key]/w3:IPAddress" />
<xsl:choose>
<xsl:when test="$address">
<xsl:value-of select="$address" />
</xsl:when>
<xsl:otherwise>None</xsl:otherwise>
</xsl:choose>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
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.
edited in response to comments *
Hello,
I am an XSLT noob and need some help. I am trying to do an filter/group combination with XSLT 1.0 (can't use XSLT 2.0 for this application).
Here is an example of the xml
<entry>
<item>
<name>Widget 2</name>
<rank>2</rank>
<types>
<type>Wood</type>
<type>Fixed</type>
<type>Old</type>
</types>
</item>
<item>
<name>Widget 1</name>
<rank>2</rank>
<types>
<type>Metal</type>
<type>Broken</type>
<type>Old</type>
</types>
</item>
<item>
<name>Widget 3</name>
<rank>1</rank>
<types>
<type>Metal</type>
<type>New</type>
</types>
</item>
</entry>
Now what I want to do is output html where I get a subset of the XML based on <type> and then group on rank. For example, if the user selects all items with the type Metal, the output should be:
<p class="nospace"><font color="#800000">
<b>Rank 1</b></font></p>
<li id="mylist"><b>Widget 3</b></li>
<br\>
<p class="nospace"><font color="#800000">
<b>Rank 2</b></font></p>
<li id="mylist"><b>Widget 1</b></li>
<br\>
of if the user user chooses the type Old the output would be
<p class="nospace"><font color="#800000">
<b>Rank 2</b></font></p>
<li id="mylist"><b>Widget 1</b></li>
<li id="mylist"><b>Widget 2</b></li>
<br\>
I can group using keys on rank along easily enough, but trying to do both is not working. Here is a sample of the xslt I have tried:
<xsl:param name="typeParam"/>
<xsl:key name="byRank" use="rank" match="item"/>
<xsl:for-each select="item[count(.|key('byRank',rank)[1])=1]">
<xsl:sort data-type="number" select="rank"/>
<xsl:for-each select="key('byRank',rank)">
<xsl:sort select="name"/>
<xsl:if test="count(rank)>0">
<p class="nospace"><font color="#800000"><b>Rank<xsl:value-of select="rank"/></b></font></p>
<xsl:for-each select="types[types=$typeParam]">
<li id="mylist"><b><xsl:value-of select="../name"/></b></li>
</xsl:for-each>
<br/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
The result I get from this is I do indeed get the subset of my xml that I want but it also displays all of the various rank values. I want to limit it to just the ranks of the type that is specified in $typeParam.
I have tried moving the for-each statement to earlier in the code as well as modifying the if statement to select for $typeParam but neither works. I have also tried concat-ing my key with rank and type but that doesn't seem to work either (It only works if the type in $typeParam is the first child under types).
Thanks
jeff
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kItemByRank" match="item" use="rank"/>
<xsl:param name="pType" select="'Old'"/>
<xsl:template match="entry">
<xsl:for-each select="item[count(.|key('kItemByRank',rank)[1])=1]">
<xsl:sort select="rank" data-type="number"/>
<xsl:variable name="vGroup" select="key('kItemByRank',rank)[
types/type = $pType
]"/>
<xsl:if test="$vGroup">
<p class="nospace">
<font color="#800000">
<b>
<xsl:value-of select="concat('Rank ',rank)"/>
</b>
</font>
</p>
<xsl:apply-templates select="$vGroup">
<xsl:sort select="name"/>
</xsl:apply-templates>
<br/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="item">
<li id="mylist">
<b>
<xsl:value-of select="name"/>
</b>
</li>
</xsl:template>
</xsl:stylesheet>
Output:
<p class="nospace">
<font color="#800000">
<b>Rank 1</b>
</font>
</p>
<li id="mylist">
<b>Widget 3</b>
</li>
<br />
<p class="nospace">
<font color="#800000">
<b>Rank 2</b>
</font>
</p>
<li id="mylist">
<b>Widget 1</b>
</li>
<br />
And whit pType param set to 'Old', output:
<p class="nospace">
<font color="#800000">
<b>Rank 2</b>
</font>
</p>
<li id="mylist">
<b>Widget 1</b>
</li>
<li id="mylist">
<b>Widget 2</b>
</li>
<br />