XSLT - Get String between commas - xslt

How can I get the value 'four' in XSLT?
<root>
<entry>(one,two,three,four,five,six)</entry>
</root>
Thanks in advance.

You didn't specify the XSLT version, so I assume version 2.0.
I also assume that word four is only a "marker", stating from which place
take the result string (between the 3rd and 4th comma).
To get the fragment you want, you can:
Use tokenize function to "cut" the whole content of entry
into pieces, using a comma as the cutting pattern.
Take the fourth element of the result array.
This expression can be used e.g. in a template matching entry.
So the example script can look like below:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="entry">
<xsl:copy>
<xsl:value-of select="tokenize(., ',')[4]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
</xsl:transform>
For your input XML it gives:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<entry>four</entry>
</root>

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>

XSLT for-each always takes only one element

I have XML which contains multiple elements:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<element>
<ip>192.168.188.101</ip>
</element>
<element>
<ip>192.168.188.100</ip>
</element>
</data>
I want to make it to this structure:
<SYNCDW>
<CIDWSet>
<CI>
<CINUM>192.168.188.101</CINUM>
</CI>
<CI>
<CINUM>192.168.188.100</CINUM>
</CI>
</CIDWSet>
</SYNCDW>
But always one element is processed, the first one, although I have for-each.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<SyncCIDW xmlns="http://www.ibm.com/maximo">
<xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance">http://www.ibm.com/maximo</xsl:attribute>
<CIDWSet>
<xsl:for-each select="*[local-name()='data' and namespace-uri()='']/*[local-name()='element' and namespace-uri()='']">
<CI>
<CINUM>
<xsl:value-of select="string(*[local-name()='data' and namespace-uri()='']/*[local-name()='element' and namespace-uri()='']/*[local-name()='ip' and namespace-uri()=''])"/>
</CINUM>
</CI>
</xsl:for-each>
</CIDWSet>
</SyncCIDW>
</xsl:template>
</xsl:stylesheet>
Why I am not getting processed all other elements but only the first one?
Thank you in advance for help
A couple of things:
Inside of the xsl:for-each, the context switches to the element that you are iterating over (in this case, /data/element), so to select the ip element your XPath is relative from the /data/element that you are "standing on" and would simply be ip. The way you had it, it would be looking for /data/element/data/element/ip inside of the xsl:for-each and would not produce any values inside of the <CINUM>.
You can simplify your XPath expressions. If the elements you are addressing are not bound to a namespace, rather than a generic match on any element and a predicate matching the local-name() and namespace-uri()='', just use the simplified XPath data/element.
If you are creating a statically known attribute xsi:schemaLocation with a statically known value, just use the literal declaration inside of the SyncCIDW element literal.
If you are using xsl:value-of it will yield the string value of the selected node. There is no need for the string() function.
Changes applied to your stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<SyncCIDW xmlns="http://www.ibm.com/maximo"
xsi:schemaLocation="http://www.ibm.com/maximo">
<CIDWSet>
<xsl:for-each select="data/element">
<CI>
<CINUM>
<xsl:value-of select="ip"/>
</CINUM>
</CI>
</xsl:for-each>
</CIDWSet>
</SyncCIDW>
</xsl:template>
</xsl:stylesheet>

Handling < > in XSLT 1.0

I have a problem, when trying to read a structure having < > in source XML.
Input Structure -
<?xml version="1.0" encoding="UTF-8"?>
<RecordsData>
<RecordsData>
<UID><RecordsData xmlns=""><RecordsData><UID>200</UID><RID>Test-1</RID><Date>20142812</Date><Status>N</Status></RecordsData></RecordsData></UID>
</RecordsData>
</RecordsData>
Expected Output Structure (there are two requirements) -
One is just conversion of < >into well formed XML tags.
<?xml version="1.0" encoding="UTF-8"?>
<RecordsData>
<RecordsData>
<UID><RecordsData xmlns=""><RecordsData><UID>200</UID><RID>Test-1</RID><Date>20142812</Date><Status>N</Status></RecordsData></RecordsData></UID>
</RecordsData>
</RecordsData>
Second is extraction of whole data inside UID tag with output as only below -
<RecordsData xmlns=""><RecordsData><UID>200</UID><RID>Test-1</RID><Date>20142812</Date><Status>N</Status></RecordsData></RecordsData>
I am able to get second output if I have first one in hand. But struggling to get first output from Input over last few days after searching forum extensively and being very new to XSLT.
If we can directly get second output from input source - it's actually what is expected solution. For above - I just tried to break down problem into steps.
Any of experts can you please help!
Thanks,
Conversion is easy, extraction is not.
To convert the escaped markup to real markup, simply disable the escaping when writing the node to the result tree, for example:
XSLT 1.0
<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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="UID">
<xsl:copy>
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Ideally, you would use the resulting XML file to extract any data from the escaped portion. Otherwise you would have to apply string functions for this purpose, since the escaped text is not XML.
However, in your example, you don't want to extract anything particular from the data, just isolate it and convert it to a stand-alone markup document. This can be easily accomplished by:
XSLT 1.0
<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:template match="/">
<xsl:value-of select="RecordsData/RecordsData/UID" disable-output-escaping="yes"/>
</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>

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>