XSLT: for-each-group select with condition - not(contains()) - xslt

I would like to get help with my problem in creating an xslt transform.
I need to get select from xsl:for-each-group with some conditions.
I need to get all elements, which sub-element have text in sub-element "Zkrat" not same as text in this array
<xsl:variable name="zkratky">
<zkratka>1</zkratka>
<zkratka>2</zkratka>
<zkratka>5</zkratka>
<zkratka>6</zkratka>
</xsl:variable>
<xsl:variable name="lookup" select="document('')//xsl:variable[#name='zkratky']"/>
My XML file input is:
<MoneyData>
<SeznamObjPrij>
<ObjPrij>
<Polozka>
<KmKarta>
<Popis>Main title</Popis>
<TypKarty>komplet</TypKarty>
<Slozeni>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item1</Popis>
<Zkrat>2</Zkrat>
<Katalog>1111</Katalog>
</KmKarta>
<PocMj>1</PocMj>
</Komponenta>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item2</Popis>
<Zkrat>1</Zkrat>
<Katalog>22222</Katalog>
</KmKarta>
<PocMj>4</PocMj>
</Komponenta>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item3</Popis>
<Zkrat>3</Zkrat>
<Katalog>1111</Katalog>
</KmKarta>
<PocMj>1</PocMj>
</Komponenta>
</Slozeni>
</KmKarta>
</Polozka>
<Polozka>
<KmKarta>
<Popis>Test</Popis>
<TypKarty>jednoducha</TypKarty>
</KmKarta>
</Polozka>
<Polozka>
<KmKarta>
<Popis>Main title</Popis>
<TypKarty>komplet</TypKarty>
<Slozeni>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item1</Popis>
<Zkrat>2</Zkrat>
<Katalog>1111</Katalog>
</KmKarta>
<PocMj>10</PocMj>
</Komponenta>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item2</Popis>
<Zkrat>2</Zkrat>
<Katalog>33333</Katalog>
</KmKarta>
<PocMj>1</PocMj>
</Komponenta>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item3</Popis>
<Zkrat>1</Zkrat>
<Katalog>1111</Katalog>
</KmKarta>
<PocMj>2</PocMj>
</Komponenta>
<Komponenta>
<KmKarta>
<Popis>Subtitle Item4</Popis>
<Zkrat>3</Zkrat>
<Katalog>4444</Katalog>
</KmKarta>
<PocMj>1</PocMj>
</Komponenta>
</Slozeni>
</KmKarta>
</Polozka>
</ObjPrij>
</SeznamObjPrij>
</MoneyData>
My xslt transform:
<xsl:for-each-group select="Polozka/KmKarta/Slozeni/Komponenta[$lookup[not(contains(., KmKarta/Zkrat))]]" group-by="KmKarta/Katalog">
<xsl:sort select="KmKarta/Popis"/>
<tr>
<td><xsl:value-of select="KmKarta/Popis"/></td>
<td><xsl:value-of select="current-grouping-key()"/></td>
<td><xsl:value-of select="KmKarta/Zkrat"/></td>
<td><xsl:value-of select="sum(current-group()/PocMJ)"/></td>
</tr>
</xsl:for-each-group>
I always get all elements or none. Or this message:
Wrong occurrence to match required sequence type
Error location: xsl:stylesheet / xsl:template / div / table / tbody / xsl:for-each-group / #select
Details
XPTY0004: The parameter value ('4' item(s)) at position '1' of the 'contains' function has the wrong occurrence to match the sequence type xs:string ('zero or one')
Please, help me.
Thank you very much :)

All sorts of things wrong here.
Firstly, if you're using for-each-group then you're using XSLT 2.0+ which means you don't need the contortion of having the stylesheet read its own global variables using document('').
There are several problems in this expression
Komponenta[$lookup[not(contains(., KmKarta/Zkrat))]]
As written, the context item for evaluating KmKarta/Zkrat is an element in $lookup, which isn't what you want.
And I don't think you need contains() here - you need "=" which makes it much simpler.
So I think you just want Komponenta[not(KmLarta/Zkrat = $zkratky/zkratka)].

I would just use
<xsl:variable name="zkratky">
<zkratka>1</zkratka>
<zkratka>2</zkratka>
<zkratka>5</zkratka>
<zkratka>6</zkratka>
</xsl:variable>
plus
<xsl:for-each-group select="Polozka/KmKarta/Slozeni/Komponenta[not($zkratky/zkratka = KmKarta/Zkrat)]" group-by="KmKarta/Katalog">

Related

Freemarker - XSLT equivalent of copy-of

I'm trying to simulate the copy-of function in XSLT where I want everything within a node outputted in the response.
Using this template
<#ftl ns_prefixes={"D": "http://milyn.codehaus.org/Smooks"} output_format="XML">
${Order.orderitem.##markup}
Facing 2 issues here
The output i get transformed the <, > as well of the XML tags. I do need XML formatting to escape invalid characters like & etc.
How can i remove the namescapes that appears in every node
My response is
<orderitem xmlns="http://milyn.codehaus.org/Smooks"><position>1</position><quantity>1</quantity><productid>364</productid><title>The 40YearOld</title><price>29.98</price></orderitem><orderitem xmlns="http://milyn.codehaus.org/Smooks"><position>2</position><quantity>1</quantity><productid>299</productid><title>Pulp Fiction</title><price>29.99</price></orderitem>
Input being
<Order xmlns="http://milyn.codehaus.org/Smooks" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance">
<header>
<orderid>1</orderid>
<statuscode>0</statuscode>
<netamount>59.97</netamount>
<totalamount>64.92</totalamount>
<tax>4.95</tax>
<date>Wed Nov 15 13:45:28 EST 2006</date>
</header>
<customerdetails>
<username>user1</username>
<name>
<firstname>Harry</firstname>
<lastname>Fletcher</lastname>
</name>
<state>South Dakota</state>
</customerdetails>
<orderitem>
<position>1</position>
<quantity>1</quantity>
<productid>364</productid>
<title>The 40YearOld</title>
<price>29.98</price>
</orderitem>
<orderitem>
<position>2</position>
<quantity>1</quantity>
<productid>299</productid>
<title>Pulp Fiction</title>
<price>29.99</price>
</orderitem>
To prevent auto-escaping: ${Order.orderitem.##markup?no_esc}. (Unfortunately XML wrapping way predates auto-escaping, so it has remained like so...)
Prevent repeated xmlns-es... you can't. The problem is that the orderitem-s has no common ancestor as far as ##markup can know, where a common xmlns could solve this, so it does the safest thing.

Traverse xml document using xpath and xsl

I am using XSL and XPATH to traverse, read and transform a complex XML file where I have multiple nodes with same names but different values. My sample xml file is below -
<core>
<address>
<postalZipCode>90017</postalZipCode>
<updateSource>xxxxxx</updateSource>
<city>LOS ANGELES</city>
<stateProvince>CA</stateProvince>
<type>MAILING</type>
<line1>818 WEST SEVENTH STREET</line1>
</address>
<address>
<postalZipCode>95014</postalZipCode>
<updateSource>xxxxxx</updateSource>
<city>CUPERTINO</city>
<stateProvince>CA</stateProvince>
<type>PRIMARY</type>
<line1>1234 XYZ STREET</line1>
</address>
<memberId>0</memberId>
</core>
When I read the MAILING ADDRESS Line 1 value , the value I am getting is "1234 XYZ STREET" which essentially is the PRIMARY ADDRESS . Here is my xsl file snippet :-
<xsl:template match="core">
<xsl:if test="memberId['0'] and address/type['MAILING']">
<fo:table-row>
<fo:table-cell><fo:block /></fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="data">
<fo:block>Line 1</fo:block>
</fo:table-cell>
<fo:table-cell xsl:use-attribute-sets="data">
<fo:block><xsl:value-of select="address/line1/text()"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
Could the experts here please suggest if there is any other way possible to force XSL to read the correct value of where address is MAILING, instead of reading the first value it finds ???
if there is any other way possible to force XSL to read the correct
value of where address is MAILING, instead of reading the first value
it finds ???
Your question is rather confusing, because MAILING is the first address in your example - and the snippet you show does not produce the result you say it does.
In any case, to make sure you get data from the MAILING address regardless of its position, change this:
<xsl:value-of select="address/line1/text()"/>
to:
<xsl:value-of select="address[type='MAILING']/line1"/>
To understand how this works, read more about predicates.
The code you have written says "if there is an address with type MAILING, then print the value of address/line1 (whether or not this is in any way related to the address with type MAILING)".
In XSLT 1.0, when xsl:value-of selects more than one node, it displays the value of the first one it finds. In XSLT 2.0 it concatenates the values of all the selected nodes, with a separator that defaults to a single space.
If there's more than one node and you want to select a specific one, then select it with a predicate, e.g. xsl:value-of select="address[#type='MAILING']/line1.

xslt transformation move data to child element

I have a source file o with the following data
#POST_START
#ID 2
#NAME John Doe
#STREET Big Street 1
#ZIP 1111111
#CITY LONDON
#POST_END
#POST_START
#ID 3
#NAME Jonathan Swift
#STREET Little Street 9
#ZIP 333333
#CITY PARIS
POST_END
I need to transform this to the following structure
<persons>
<person>
<id>2</id>
<name>John Doe</name>
<address>
<street>Big Street</street>
<zip>111111</zip>
<city>LONDON</city>
</address>
</person>
<person>
<id>3</id>
<name>Jonathan Swift</name>
<address>
<street>Little Street</street>
<zip>333333</zip>
<city>PARIS</city>
</address>
</person>
</persons>
What is the best way to achive this? I´ve tried and managed to get most part right, but i don´t seem to be able to insert the address element and "push down" the street, zip and city to a child level.
Any help appreciated.

conditional match for multiple attributes using XSLT

Below is the input XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:ces:names:specification:ces:schema:all:4:0">
<soapenv:Header/>
<soapenv:Body>
<ces:ShipNotice Version="4.0" xmlns:ces="urn:ces:names:specification:ces:schema:all:4:0">
<ces:Header>
<ces:From>
</ces:From>
<ces:To>
</ces:To>
</ces:Header>
<ces:ShipNoticeBody>
<ces:ShipNoticePartners>
<ces:Buyer>
<ces:PartnerInformation>
<ces:PartnerIdentifier Agency="AGIIS-EBID">8049915600000</ces:PartnerIdentifier>
</ces:PartnerInformation>
</ces:Buyer>
<ces:OtherPartner PartnerRole="ShipTo">
<ces:PartnerInformation>
<ces:PartnerIdentifier Agency="AGIIS-EBID">8049915600000</ces:PartnerIdentifier>
</ces:PartnerInformation>
</ces:OtherPartner>
<ces:OtherPartner PartnerRole="BillToParty">
<ces:PartnerInformation>
<ces:PartnerIdentifier Agency="AGIIS-EBID">1024122440000</ces:PartnerIdentifier>
</ces:PartnerInformation>
</ces:OtherPartner>
</ces:ShipNoticePartners>
<ces:ShipNoticeDetails>
</ces:ShipNoticeDetails>
</ces:ShipNoticeBody>
</ces:ShipNotice>
</soapenv:Body>
</soapenv:Envelope>
I need to test for incoming request if the value of Buyer and Shipto and Billtoparty can be AGIIS-EBID or EAN.
I did ask similar question before
Previous thread
In previous thread the value I was testing was same.
<xsl:when test="
($Buyer='AGIIS-EBID' and $Shipto='AGIIS-EBID' and $Billto='AGIIS-EBID')
or ($Buyer='EAN' and $Shipto='EAN' and $Billto='EAN')
or ($Buyer='GLN' and $Shipto='GLN' and $Billto='GLN')">
My question is how to test the condition for Agency#Buyer, Agency#Shipto, Agency#billtoParty if the value will be AGIIS-EBID or EAN
I mean in the soap request always Buyer,Shipto, billtoparty can have different sequence like Buyer=AGIIS-EBID,Shipto=EAN,billtoparty=AGIIS-EBID or Buyer=EAN,Shipto=EAN,billtoparty=AGIIS-EBID or Buyer=AGIIS-EBID,Shipto=EAN,billtoparty=EAN
I was thinking to do something like this
<xsl:when test="($Buyer='AGIIS-EBID' and $Shipto='AGIIS-EBID' and $Billto='AGIIS-EBID') or ($Buyer='AGIIS-EBID' and $Shipto='EAN' and $Billto='AGIIS-EBID')($Buyer='AGIIS-EBID' and $Shipto='AGIIS-EBID' and $Billto='EAN') or ($Buyer='EAN' and $Shipto='EAN' and $Billto='EAN')">
Can anyone please advise for different approach?
Update for the questions.
#michael.hor257k I am sorry.. three agency objects (Buyer, ShipTo and BillToParty), You are correct it can be positive ( AGIIS-EBID or EAN).. If it is positive I need to accept the message, however if its negative I need to reject the message saying #Agency didn't match the AGIIS or EAN for buyer and Shipto and Billparty.
The problem I am facing is Agency objects (Buyer, ShipTo and BillToParty) should match ( AGIIS-EBID or EAN), but in what manner they come I don't know.
Below are the different ways values may get assigned.
Eg: (Buyer='AGIIS-EBID'and Shipto='EAN'and Billtoparty='AGIIS-EBID') or (Buyer='EAN' and Shipto='EAN' and Billtoparty='AGIIS-EBID') or (Buyer='AGIIS-EBID' and Shipto='EAN' and Billtoparty='EAN')` so on ....
One more thing I want to add I have to check the positive condition for #Agency in Buyer and Shipto and BilltoParty
My goal to test every time $Buyer= 'AGIIS-EBID' or 'EAN' and $Shipto=
'AGIIS-EBID' or 'EAN' and $Billto= 'AGIIS-EBID' or 'EAN'
Okay, so why don't you just spell that out as;
<xsl:when test="
($Buyer='AGIIS-EBID' or $Buyer='EAN')
and
($Shipto='AGIIS-EBID' or $Shipto='EAN')
and
($Billto='AGIIS-EBID' or $Billto='EAN')">
How about:
<xsl:variable name="Buyer_ok" select=" $Buyer = 'EAN' or $Buyer = 'AGIIS-EBID' " />
<xsl:variable name="Shipto_ok" select=" $Shipto = 'EAN' or $Shipto = 'AGIIS-EBID' " />
<xsl:variable name="Billto_ok" select=" $Billto = 'EAN' or $Billto = 'AGIIS-EBID' " />
:
:
<xsl:when test=" $Buyer_ok and $Shipto_ok and $Billto_ok "> . . .</xsl:when>

Need to remove Note: from the start of a string using XSLT

I have been tasked with styling XML and so far nearly all of the tags I have been given are either p or ph which just display the contents of the tag on screen and I can style as required
eg:
<p outputclass="LC AStatProv">Council Regulation (EC) No 2201/2003 of 27 November 2003 Concerning Jurisdiction and the Recognition and Enforcement of Judgments in Matrimonial Matters and in Matters of Parental Responsibility, repealing Regulation (EC) No 1347/2000 (Brussels II Revised) (2003) OJ L 338/1, Art 20</p>
will display as:
Council Regulation (EC) No 2201/2003 of 27 November 2003 Concerning Jurisdiction and the Recognition and Enforcement of Judgments in Matrimonial Matters and in Matters of Parental Responsibility, repealing Regulation (EC) No 1347/2000 (Brussels II Revised) (2003) OJ L 338/1, Art 20
Today I have noticed that a new note tag has been used and this is causing "Note: " to be prepended to the beginning of each string eg:
<p outputclass="LC ACourt"><note outputclass="CaseSearchCourt">Court of Appeal</note></p>
will display as:
Note: Re A (Abduction: Interim Directions: Accommodation by Local Authority) [2010] EWCA Civ 586 [2011] 1 FLR 1
The FO produced for this is:
<fo:block><fo:inline font-weight="bold" border-right-width="0pt" border-left-width="0pt">Note: </fo:inline> Court of Appeal</fo:block>
I have tried the following code gleaned from elsewhere on this site but it didn't remove the string I wanted:
<xsl:template match="note">
<note>
<xsl:if test="contains(., 'Note:')">
<xsl:call-template name="remove">
<xsl:with-param name="value" select="."/>
</xsl:call-template>
</xsl:if>
</note>
</xsl:template>
<xsl:template name="remove">
<xsl:param name="value"/>
<xsl:value-of select="concat(substring-before($value, 'Note:'), substring-after($value, 'Note:'))"/>
</xsl:template>
I have tried to see where XSLT gets the "Note: " from but can't find it anywhere so my next thought is to try and pattern match the string and remove "Note: " from the beginning of the string. Is this a good way to go about this and how would I do this?
thanks.
EDIT: Just to summarise my rambling and confusing question.
Where it renders:
Note: Re A (Abduction: Interim Directions: Accommodation by Local Authority) [2010] EWCA Civ 586 [2011] 1 FLR 1
I just want it to render:
Re A (Abduction: Interim Directions: Accommodation by Local Authority) [2010] EWCA Civ 586 [2011] 1 FLR 1
EDIT 2 and the answer
My initial investigations were based upon grepping for Note: which wasn't being found. I have though found the following:
<xsl:template match="*[contains(#class,' topic/note ')]">
and then commented out the following lines:
<!--<xsl:text>Note</xsl:text>-->
</xsl:otherwise>
</xsl:choose>
<!--<xsl:text>: </xsl:text>-->
</fo:inline>
<xsl:text> </xsl:text>
<xsl:apply-templates/>
And I have got rid of the "Note: ".
EDIT 3:
This didn't actually work as it created an opening block but didn't close it so I ended up removing the entire <xsl:template match="*[contains(#class,' topic/note ')]"> as we have no need for any type of notes in our system
This didn't actually work as it created an opening block but didn't close it so I ended up removing the entire <xsl:template match="*[contains(#class,' topic/note ')]"> as we have no need for any type of notes in our system