Restrict occurrence of Line item based on input condition in xslt - xslt

I need to populate the line item E1EP01 in output structure only if the value of E1EP01/CODE = WK30 and E1EP01/E1EP19/TEXT is not blank , in input file.
I have written below line of codes but E1EP01 is not appearing in Output even if CODE has value equal to WK30 and TEXT is not blank
Can anyone please help me in this?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<ORDERS05>
<IDOC>
<xsl:if test=" ZXX/IDOC/E1EP01/CODE = &apos;WK30&apos; and ZXX/IDOC/E1EP01/E1EP19/TEXT!= &apos; &apos;">
<xsl:for-each select="E1EP01">
<E1EP01>
<POSEX>
<xsl:value-of select="ZXX/IDOC/E1EP01/POSEX"/>
</POSEX>
</E1EP01>
</xsl:for-each>
</xsl:if>
</IDOC>
</ORDERS05>
</xsl:template>
</xsl:stylesheet>
Sample input is shown below:
<?xml version="1.0" encoding="UTF-8"?>
<ZXX>
<IDOC BEGIN="1">
<E1EP01 SEGMENT="1">
<POSEX>00020</POSEX>
<CODE>WN14</WERKS>
<E1EP19 SEGMENT="1">
<Q>001</Q>
<TEXT>000000000000204034</TEXT>
</E1EP19>
</E1EP01>
<E1EP01 SEGMENT="1">
<POSEX>00010</POSEX>
<WERKS>WK30</WERKS>
<E1EP19 SEGMENT="1">
<Q>001</Q>
<TEXT>000000000000205115</TEXT>
</E1EP19>
</E1EP01>
</IDOC>
</ZXX>

Change:
<xsl:for-each select="E1EP01">
to:
<xsl:for-each select="ZXX/IDOC/E1EP01">
Note: you don't need to escape single quotes as &apos; in your test expression.
Added:
I need to test each E1EP01 for the condition and if condition matches
then that E1EP01 should appear in output.
Try it this way, then:
XSLT 1.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/ZXX">
<ORDERS05>
<IDOC>
<xsl:for-each select="IDOC/E1EP01[CODE='WK30' and E1EP19/TEXT!='']">
<xsl:copy>
<xsl:copy-of select="POSEX"/>
</xsl:copy>
</xsl:for-each>
</IDOC>
</ORDERS05>
</xsl:template>
</xsl:stylesheet>

Related

How to use count specific element and get count value on target xml from source xml using xslt?

I wanna read the element count and apply the target xml element from a specific source element.
this is source xml to be read and counting POSEX field
<?xml version="1.0" encoding="UTF-8"?>
<INVOIC01>
<IDOC>
<POSEX>000010</POSEX>
<MENGE>1.000</MENGE>
<MENEE>EA</MENEE>
<GEWEI>KGM</GEWEI>
<BRGEW>13.000</BRGEW>
<PSTYV>TAN</PSTYV>
<WERKS>3000</WERKS>
</IDOC>
<IDOC>
<POSEX>000010</POSEX>
<MENGE>1.000</MENGE>
<MENEE>EA</MENEE>
<GEWEI>KGM</GEWEI>
<BRGEW>13.000</BRGEW>
<PSTYV>TAN</PSTYV>
<WERKS>3000</WERKS>
</IDOC>
</INVOIC01>
my xslt code
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates select="*"/>
</xsl:template>
<!-- ============================================================================================= -->
<!-- Template: Enter the ordinal number in POSEX-->
<!-- ============================================================================================= -->
<xsl:template match="POSEX">
<D_6066>
<xsl:value-of select="count(preceding::POSEX)+1"/>
</D_6066>
</xsl:template>
</xsl:stylesheet>
outcome xml after run xslt code
<?xml version="1.0" encoding="UTF-8"?>
<D_6066>1</D_6066>
1.000
EA
KGM
13.000
TAN
3000
<D_6066>2</D_6066>
1.000
EA
KGM
13.000
TAN
3000
I want to expect target xml as below after run xslt.
<D_6066>2</D_6066>
If I understand correctly, you want your output document to consist of a single D_6066 element containing the count of the number of POSEX elements in the input document.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<D_6066>
<xsl:value-of select="count(//POSEX)"/>
</D_6066>
</xsl:template>
</xsl:stylesheet>

Add Values of a field specific to input value of another field

I have a requirement which is to be achieved using xslt. It requires to add only those values of field 'NETWR' under E1EDP01, when another field WERKS under E1EDP01 satisfies a certain condition. This added sum is to be populated under different node field SUMME under E1EDS01 (Occurrence of E1EDS01 is only one). Condition for WERKS is , it must have value = VK10 0r VK11 0r VK12 or (VK13 and IDTNR is not blank). I tried with below XSLT code but it gives me value '0'in output.Could anyone please help?
XSLT I used:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<ZNUMBER>
<IDOC>
<xsl:for-each select="Z_MM/IDOC/E1EDS01">
<E1EDS01>
<SUMME>
<xsl:value-of select="sum(Z_MM/IDOC/E1EDP01[(WERKS=&apos;VK13&apos; and E1EDP19/IDTNR!=&apos;&apos;) or WERKS = &apos;VK10&apos; or WERKS = &apos;VK11&apos; or WERKS = &apos;VK12&apos; ]/#NETWR)"/>
</SUMME>
</E1EDS01>
</xsl:for-each>
</IDOC>
</ZNUMBER>
</xsl:template>
</xsl:stylesheet>
INPUT XML:
<?xml version="1.0" encoding="UTF-8"?>
<Z_MM>
<IDOC BEGIN="1">
<E1EDP01 SEGMENT="1">
<NETWR>20</NETWR>
<WERKS>VK13</WERKS>
<E1EDP19 SEGMENT="1">
<IDTNR>000000000000211087</IDTNR>
</E1EDP19>
</E1EDP01>
<E1EDP01 SEGMENT="1">
<NETWR>10</NETWR>
<WERKS>VK11</WERKS>
<E1EDP19 SEGMENT="1">
<QUALF>001</QUALF>
</E1EDP19>
</E1EDP01>
<E1EDS01 SEGMENT="1">
<SUMID>002</SUMID>
<SUMME></SUMME>
<SUNIT></SUNIT>
</E1EDS01>
</IDOC>
</Z_MM>
OUTPUT should come as 20+10=30
Your current sum function is within an xsl:for-each in which you select E1EDS01 elements, so you expression is relative to that. In other words, it is looking for a child element of E1EDS01 called ZM1. If you want to search outside the current element, precede the expression / to start at the document node again. Additionally your expression is currently summing #NEWTR which is an attribute, whereas in your XML it is an element.
Try this expression.
<xsl:value-of select="sum(/Z_MM/IDOC/E1EDP01[(WERKS='VK13' and E1EDP19/IDTNR!='') or WERKS = 'VK10' or WERKS = 'VK11' or WERKS = 'VK12']/NETWR)"/>
Having said that, looking at your current XSLT, you don't really need the xsl:for-each at all in this case, as you say there is only one E1EDS01 and you are not actually using any value in it anyway.
Try this XSLT (The / is not needed here now, because you would already be positioned on the document node).
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<ZNUMBER>
<IDOC>
<E1EDS01>
<SUMME>
<xsl:value-of select="sum(Z_MM/IDOC/E1EDP01[(WERKS='VK13' and E1EDP19/IDTNR!='') or WERKS = 'VK10' or WERKS = 'VK11' or WERKS = 'VK12']/NETWR)"/>
</SUMME>
</E1EDS01>
</IDOC>
</ZNUMBER>
</xsl:template>
</xsl:stylesheet>
Alternatively, if you XSLT is a sample, and you actually just want to populate the existing SUMME, you could do this with the identity template, and an extra template to match SUMME.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="SUMME">
<xsl:copy>
<xsl:value-of select="sum(/Z_MM/IDOC/E1EDP01[(WERKS='VK13' and E1EDP19/IDTNR!='') or WERKS = 'VK10' or WERKS = 'VK11' or WERKS = 'VK12']/NETWR)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Sum function in XSL

The Below is my input XML:
<?xml version="1.0" encoding="utf-8" ?>
<LogiusInhouse>
<qty9 field="QTY_9,11#">
<type>90</type>
<value>12</value>
</qty9>
<qty9 field="QTY_9,11#">
<type>90</type>
<value>12</value>
</qty9>
<dtm9 field="DTM_9,11#">
<type>145</type>
<date>20130308</date>
<format>102</format>
</dtm9>
</LogiusInhouse>
XSL:
<xsl:template match="/LogiusInhouse">
<xsl:value-of select="abs(sum(qty9[type='90']/value))div 1000 "/>
</xsl:template>
my problem is i need to get the absolute sum afterthat it has to be divided by 1000 but iam not getting the result.Please help me on this.
Or, you can use just this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/LogiusInhouse">
<xsl:value-of select="sum(qty9/value)" />
</xsl:template>
</xsl:stylesheet>
do not use for-each. use the template below
<xsl:template match="/LogiusInhouse">
<xsl:value-of select="sum(//value)"/>
</xsl:template>
using for-each will output 1212 because for-each node (in your code), the result is 12

change of xml structure using xslt

I want to convert the following source xml structure to the target xml structure using xslt transformation. I am mot able to convert the following source xml to target xml using xslt. Please help us in coneverting this.
Source XML
<XxhrPiEmpcompOutIntCollection>
<XxhrPiEmpcompOutInt>
<employeeNumber>
200000562
</employeeNumber>
<competencyName>
Comp1
</competencyName>
<proficiencyLevel>
Prof1
</proficiencyLevel>
<compDateTo>
16-NOV-12
</compDateTo>
</XxhrPiEmpcompOutInt>
<XxhrPiEmpcompOutInt>
<employeeNumber>
200000562
</employeeNumber>
<competencyName>
Comp2
</competencyName>
<proficiencyLevel>
Prof2
</proficiencyLevel>
<compDateTo>
16-NOV-12
</compDateTo>
</XxhrPiEmpcompOutInt>
</XxhrPiEmpcompOutIntCollection>
Target xml
<EmployeeCompetencyRequest>
<EmployeeNumber>200000562</EmployeeNumber>
<Competencies>
<Competency>
<Name>Comp1</Name>
<ProficiencyLevel>Prof1</ProficiencyLevel>
<EndDate>16-NOV-12</EndDate>
</Competency>
<Competency>
<Name>Comp2</Name>
<ProficiencyLevel>Prof2</ProficiencyLevel>
<EndDate>16-NOV-12</EndDate>
</Competency>
</Competencies>
</<EmployeeCompetencyRequest>
Some hint :
<EmployeeCompetencyRequest>
template match /XxhrPiEmpcompOutIntCollection
for-each-group XxhrPiEmpcompOutInt group by employeeNumber
<EmployeeNumber> value-of current-group-key </EmployeeNumber>
<Competencies>
for-each current-group
<Competency>
value-of name
value-of proficiencyLevel
</competency>
/for-each
</Competencies>
/for-each-group
<EmployeeCompetencyRequest>
Hope you can finish it.
You can group users with for-each-group:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<EmployeeCompetencyRequest>
<xsl:for-each-group select="//XxhrPiEmpcompOutInt" group-by="employeeNumber">
<Name><xsl:value-of select="current-grouping-key()"/></Name>
<Competencies>
<xsl:for-each select="current-group()">
<Competency>
<Name><xsl:value-of select="competencyName"/></Name>
<ProfiencyLevel><xsl:value-of select="profiencyLevel"/></ProfiencyLevel>
<EndDate><xsl:value-of select="compDateTo"/></EndDate>
</Competency>
</xsl:for-each>
</Competencies>
</xsl:for-each-group>
</EmployeeCompetencyRequest>
</xsl:template>
Salut,
For XSLT 1.0 you must group widht xsl:key:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="groups" match="/XxhrPiEmpcompOutIntCollection/XxhrPiEmpcompOutInt" use="employeeNumber" />
<xsl:template match="/">
<EmployeeCompetencyRequest>
<xsl:apply-templates select="//XxhrPiEmpcompOutInt[generate-id() = generate-id(key('groups', employeeNumber)[1])]"/>
</EmployeeCompetencyRequest>
</xsl:template>
<xsl:template match="XxhrPiEmpcompOutInt">
<Name><xsl:value-of select="employeeNumber"/></Name>
<Competencies>
<xsl:for-each select="key('groups', employeeNumber)">
<Competency>
<Name><xsl:value-of select="competencyName"/></Name>
<ProfiencyLevel><xsl:value-of select="proficiencyLevel"/></ProfiencyLevel>
<EndDate><xsl:value-of select="compDateTo"/></EndDate>
</Competency>
</xsl:for-each>
</Competencies>
</xsl:template>
</xsl:stylesheet>
I can't test it with Oracle ...

XSL: How to concatenate nodes with conditions?

I have the following code (eg):
<response>
<parameter>
<cottage>
<cot>
<res>
<hab desc="Lakeside">
<reg cod="OB" prr="600.84>
<lwz>TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120830#20120831#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120831#20120901#EU#3-0#</lwz>
I need to create a concatenated string that includes the whole of the first 'lwz' line and then the price (200.26, but it can be different in each line) for each corresponding line.
So the output, separating each line with | would be:
TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#|200.26|200.26
Thanks
This XSLT 1.0 transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="lwz[1]">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="lwz[position() >1]">
<xsl:value-of select=
"concat('
',
substring-before(substring-after(substring-after(substring-after(.,'#'),'#'),'#'),'#')
)
"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the provided text (converted to a well-formed XML document !!!):
<response>
<parameter>
<cottage>
<cot>
<res>
<hab desc="Lakeside">
<reg cod="OB" prr="600.84">
<lwz>TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120830#20120831#EU#3-0#</lwz>
<lwz>TR#2#AB#200.26#0#QB#OK#20120831#20120901#EU#3-0#</lwz>
</reg>
</hab>
</res>
</cot>
</cottage>
</parameter>
</response>
produces the wanted, correct result:
TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#
200.26
200.26
II XSLT 2.0 solution:
This transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="lwz[1]">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="lwz[position() >1]">
<xsl:value-of select=
"concat('
', tokenize(.,'#')[4])"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
when applied on the above XML document, again produces the wanted, correct result. Note the use of the standard XPath 2.0 function tokenize():
TR#2#AB#200.26#0#QB#OK#20120829#20120830#EU#3-0#
200.26
200.26
You can use the XPath substring function to select substrings from your lwz node data. You don't really give much more detail about your problem, if you want a more detailed answer, perhaps provide the full XML document and your best-guess XSLT