How to use count specific element and get count value on target xml from source xml using xslt? - 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>

Related

I need to remove a node from an XML based on a Condition using Group by

I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<EMPLOYEE_ASSIGNMENT>
<REFRESH_DATE>2022-03-10 10:55:35.000</REFRESH_DATE>
<PERSON_ID>11189</PERSON_ID>
<EMPLOYEE_ID>032656300</EMPLOYEE_ID>
<EFFECTIVE_START_DATE>2020-08-19 00:00:00.000</EFFECTIVE_START_DATE>
<EFFECTIVE_END_DATE>4712-12-31 00:00:00.000</EFFECTIVE_END_DATE>
<BUSINESS_PROCESS>Absence Return for XXXXXXXXX last day of absence on 08/18/2020, first day back at work on 08/19/2020</BUSINESS_PROCESS>
<ACT_ASSIGNMENT_STATUS_TYPE_ID>1</ACT_ASSIGNMENT_STATUS_TYPE_ID>
<ACT_ORGANIZATION_ID>601</ACT_ORGANIZATION_ID>
<ACT_JOB_QUINTIQ_POSITION>Trainee</ACT_JOB_QUINTIQ_POSITION>
<ACT_HOURS_PER_WEEK>37.5</ACT_HOURS_PER_WEEK>
<ACT_HOURS_FREQUENCY>W</ACT_HOURS_FREQUENCY>
<ACT_BARGAINING_UNIT_CODE>C</ACT_BARGAINING_UNIT_CODE>
<ACT_PRIMARY_PROVINCE>BC</ACT_PRIMARY_PROVINCE>
</EMPLOYEE_ASSIGNMENT>
<EMPLOYEE_ASSIGNMENT>
<REFRESH_DATE>2022-03-10 10:55:35.000</REFRESH_DATE>
<PERSON_ID>11189</PERSON_ID>
<EMPLOYEE_ID>032656300</EMPLOYEE_ID>
<EFFECTIVE_START_DATE>2020-08-19 00:00:00.000</EFFECTIVE_START_DATE>
<EFFECTIVE_END_DATE>4712-12-31 00:00:00.000</EFFECTIVE_END_DATE>
<BUSINESS_PROCESS>Data Change: XXXXXXXXXXXX</BUSINESS_PROCESS>
<ACT_ASSIGNMENT_STATUS_TYPE_ID>1</ACT_ASSIGNMENT_STATUS_TYPE_ID>
<ACT_ORGANIZATION_ID>856</ACT_ORGANIZATION_ID>
<ACT_JOB_QUINTIQ_POSITION>Employee</ACT_JOB_QUINTIQ_POSITION>
<ACT_HOURS_PER_WEEK>37.5</ACT_HOURS_PER_WEEK>
<ACT_HOURS_FREQUENCY>W</ACT_HOURS_FREQUENCY>
<ACT_BARGAINING_UNIT_CODE>C</ACT_BARGAINING_UNIT_CODE>
<ACT_PRIMARY_PROVINCE>MB</ACT_PRIMARY_PROVINCE>
</EMPLOYEE_ASSIGNMENT>
</root>
The two nodes have the same EFFECTIVE_START_DATE but different BUSINESS_PROCESS for a single EMPLOYEE_ID. I need to transform that XML in a way that: when Two (or more) BUSINESS_PROCESS are present for and EMPLOYEE_ID on the same EFFECTIVE_START_DATE it shows only the one that is of value Data Change: XXXXXXXXX.
I need to transform it to:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<EMPLOYEE_ASSIGNMENT>
<REFRESH_DATE>2022-03-10 10:55:35.000</REFRESH_DATE>
<PERSON_ID>11189</PERSON_ID>
<EMPLOYEE_ID>032656300</EMPLOYEE_ID>
<EFFECTIVE_START_DATE>2020-08-19 00:00:00.000</EFFECTIVE_START_DATE>
<EFFECTIVE_END_DATE>4712-12-31 00:00:00.000</EFFECTIVE_END_DATE>
<BUSINESS_PROCESS>Data Change: XXXXXXXXXXXX</BUSINESS_PROCESS>
<ACT_ASSIGNMENT_STATUS_TYPE_ID>1</ACT_ASSIGNMENT_STATUS_TYPE_ID>
<ACT_ORGANIZATION_ID>856</ACT_ORGANIZATION_ID>
<ACT_JOB_QUINTIQ_POSITION>Employee</ACT_JOB_QUINTIQ_POSITION>
<ACT_HOURS_PER_WEEK>37.5</ACT_HOURS_PER_WEEK>
<ACT_HOURS_FREQUENCY>W</ACT_HOURS_FREQUENCY>
<ACT_BARGAINING_UNIT_CODE>C</ACT_BARGAINING_UNIT_CODE>
<ACT_PRIMARY_PROVINCE>MB</ACT_PRIMARY_PROVINCE>
</EMPLOYEE_ASSIGNMENT>
</root>
Thanks a lot
This is difficult to follow. If (!) I understand your description correctly, you want to do:
XSLT 2.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="/root">
<xsl:copy>
<xsl:for-each-group select="EMPLOYEE_ASSIGNMENT" group-by="concat(EMPLOYEE_ID,'|', EFFECTIVE_START_DATE)">
<xsl:copy-of select="current-group()[starts-with(BUSINESS_PROCESS, 'Data Change:')]"/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Biztalk Map node validation

I'm mapping home, work and mobile number nodes from the source schema to the home, work and mobile node in the destination schema.
I need to ensure that the data matches destination pattern (No space, punctuation, leading zeros, matching [+0][0-9]*. Can this be achieved via XSLT?
Source
<HTelephone>01656 123 123</HTelephone>
<WTelephone>01656-123-123</WTelephone>
<MTelephone>+447656 123 123</MTelephone>
Destination
<HTelephone>01656123123</HTelephone>
<WTelephone>01656123123</WTelephone>
<MTelephone>+447656123123</MTelephone>
Current Inline XSLT Call Template
<xsl:template name="MNo" xmlns:msxsl="urn:schemas-microsoft-com:xslt" >
<xsl:param name="inTelNo"/>
<xsl:element name="MTelephone" >
<xsl:value-of select="concat('+', translate($inTelNo, translate($inTelNo,'0123456789',''), ''))"/>
</xsl:element>
We need to validation the first character to allow a 0 or + also, any ideas?
Assuming correct input ( a root element to make it well-formed XML) use the concat() and translate functions to change the strings.
Input
<?xml version="1.0" encoding="utf-8"?>
<root>
<HTelephone>01656 123 123</HTelephone>
<WTelephone>01656 123 123</WTelephone>
<MTelephone>01656 123 123</MTelephone>
</root>
Stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/*">
<xsl:copy>
<xsl:value-of select="concat('+',translate(.,' ',''))"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Output
<?xml version="1.0" encoding="utf-8"?>
<root>
<HTelephone>+01656123123</HTelephone>
<WTelephone>+01656123123</WTelephone>
<MTelephone>+01656123123</MTelephone>
</root>

Extract node value by calculating absolute position

My source XML looks:
<test>
<text1>Test</text1>
<text2>Test</text2>
<text2>Test</text2>
<section>
<text1>Test<bold>content</bold></text1>
<text1>Test</text1>
<text2>Test</text2>
<text2>Test</text2>
</section>
</test>
Want to extract the value of 6th node, based on the absolute number of the element (overall count). The absolute number of the element has been identified using <xsl:number level="any" from="/" count="*"/>.
The XPath expression /descendant::*[6] should give you the element you need.
<xsl:template match="/">
<xsl:copy-of select="/descendant::*[6]" />
</xsl:template>
outputs
<text1>Test<bold>content</bold></text1>
Note that this is an example of the difference between descendant:: and // - //*[6] would give you all elements that are the sixth child element of their respective parent, rather than simply the sixth element in the document in depth-first order.
This xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="allElements" select="//element()" />
<xsl:template match="/">
<output>
<xsl:value-of select="$allElements[6]" />
</output>
</xsl:template>
</xsl:stylesheet>
will result in
<?xml version="1.0" encoding="UTF-8"?>
<output>Testcontent</output>

XSLT transforming name value pairs to its corresponding XML

I am new to XSLT I am trying to transform a name value pair to its corresponding XML. This feature is primarily used in case of special extensions to a standard.
The file I want to transform is the following. There are no spaces expected in any of the extNames.
<?xml version="1.0" encoding="UTF-8"?>
<extensionItems xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ExtensionItems.xsd">
<extensionsItem>
<extName> callCode</extName>
<extValue>1</extValue>
<extType>integer</extType>
</extensionsItem>
<extensionsItem>
<extName>callbackType</extName>
<extValue>All</extValue>
<extType>string</extType>
</extensionsItem>
<extensionsItem>
<extName>callbackEmail</extName>
<extValue>me#mine.org</extValue>
<extType>string</extType>
</extensionsItem>
</extensionItems>
to the following:
<ODEventNotificationExtraField>
<callCode> 1</callCode>
<callbackType> All </callbackType>
<callbackEmail> me#mine.org </callbackEmail>
</ODEventNotificationExtraField>
The following stylesheet produces the desired result:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="extensionItems">
<ODEventNotificationExtraField>
<xsl:apply-templates/>
</ODEventNotificationExtraField>
</xsl:template>
<xsl:template match="extensionsItem">
<xsl:element name="{extName}">
<xsl:value-of select="extValue"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

XSLT node Traversal

Here is a snip-it of the XML:
<?xml version="1.0" encoding="iso-8859-1" ?>
<NetworkAppliance id="S123456">
<Group id="9">
<Probe id="1">
<Value>74.7</Value>
</Probe>
</NetworkAppliance>
I want to get the single point value of 74.7. There are many groups with unique ID's and many Probes under that group with unique ID's each with values.
I am looking for example XSLT code that can get me this one value. Here is what i have that does not work:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="3.2" />
<xsl:template match="NetworkAppliance">
<xsl:apply-templates select="Group[#id='9']"/>
</xsl:template>
<xsl:template match="Group">
Temp: <xsl:value-of select="Probe[#id='1']/Value"/>
<br/>
</xsl:template>
</xsl:stylesheet>
Here is what worked for me in the end:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="NetworkAppliance/Group[#id=9]/Probe[#id=1]">
Value: <xsl:value-of select="Value" />
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Don't forget that you can do select several levels at once. Fixing your XML to:
<?xml version="1.0" encoding="iso-8859-1" ?>
<NetworkAppliance id="S123456">
<Group id="9">
<Probe id="1">
<Value>74.7</Value>
</Probe>
</Group>
</NetworkAppliance>
and using this stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="3.2" />
<xsl:template match="/">
Temp: <xsl:value-of select="//Group[#id='9']/Probe[#id='1']/Value"/>
<br/>
</xsl:template>
</xsl:stylesheet>
we can pick out that one item you're interested in.
Points to note:
The // part of the expression means that the search for Group nodes takes place throughout the whole tree, finding Group nodes at whatever depth they're at.
The [#id='9'] part selects those Group nodes with id of 9
The Probe[#id='1'] part immediately after that selects those children of the Group nodes it found where the id is 1, and so on.
<xsl:value-of select="/NetworkAppliance/Group[#id=9]/Probe[#id=1]/Value"/>
XSLT is just one of the tools in the box, and nothing without XPath.
the xpath for value of a node is /node/text()
So
<xsl:value-of select="Probe[#id='1']/text()"/>