Parent text with child content in the middle of it - xslt-2.0

I have this XML code
<parag>blah blah blah</parag>
<parag>blah blah, refer to <linkCode code1="a" code2="b" code3="c"/> for further details.</parag>
I can't figure out how to get the link to stay in the middle of the parent text. The following code
<xsl:for-each select="parag">
<p><xsl:value-of select="text()"/>
<xsl:for-each select="linkCode">
this link
</xsl:for-each>
</p>
</xsl:for-each>
produces
<p>blah blah blah</p>
<p>blah blah, refer to for further details.this link</p>
What I want is
<p>blah blah blah</p>
<p>blah blah, refer to this link for further details.</p>
Any ideas? No, I don't have control over the content of the XML.

Use just simple overriding of the identity rule:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="linkCode">
this link
</xsl:template>
<xsl:template match="parag">
<p><xsl:apply-templates select="node()|#*"/></p>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following XML document (the provided fragment wrapped into a single top element -- to get a well-formed XML document):
<t>
<parag>blah blah blah</parag>
<parag>blah blah, refer to <linkCode code1="a" code2="b" code3="c"/> for further details.</parag>
</t>
the wanted, correct result is produced:
<t>
<p>blah blah blah</p>
<p>blah blah, refer to this link for further details.</p>
</t>
And if you want to have the top element not output:
just add this template:
<xsl:template match="/*"><xsl:apply-templates/></xsl:template>
So, the complete code becomes:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="linkCode">
this link
</xsl:template>
<xsl:template match="parag">
<p><xsl:apply-templates select="node()|#*"/></p>
</xsl:template>
<xsl:template match="/*"><xsl:apply-templates/></xsl:template>
</xsl:stylesheet>

Related

Convert Date from DD-MMM-YYYY to YYYY-MMM-DD using xslt 2.0

I have a XML that has a date formatted as (2019-Aug-19) (YYYY-MMM-DD).
I want this to be transformed to (2019-08-19) (YYYY-MM-DD)
Hear is a sample what i have done. But no luck
<xsl:value-of select="format-dateTime(xs:dateTime(concat(date, T00:00:00Z')), '[D01]-[M01]-[Y0001]')"/>
Here you go may be another simple method:
XML:
<time>2019-Aug-19T00:00:00Z</time>
XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:output method="text" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:variable name="dt" select="time"/>
<xsl:template match="/">
<xsl:value-of select="format-dateTime(xs:dateTime(replace($dt, substring-before(substring-after($dt,'-'),'-') ,format-number(index-of(('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov', 'dec'),lower-case(substring-before(substring-after(lower-case($dt),'-'), '-'))),'00'))),'[D01]-[M01]-[Y0001]')"/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
Result:
19-08-2019
For YYYY-MM-DD you can do:
<xsl:value-of select="format-dateTime(xs:dateTime(replace($dt, substring-before(substring-after($dt,'-'),'-') ,format-number(index-of(('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov', 'dec'),lower-case(substring-before(substring-after(lower-case($dt),'-'), '-'))),'00'))),'[Y0001]-[M01]-[D01]')"/>
Result:
2019-08-19
See Link: http://xsltransform.net/nbiCsZm

Change in `<Output>' element with if condition

I have two input files like:
a.xml
<a>
<data>...</data>
</a>
b.xml
<b>
<data>...</data>
</b>
my xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I want to check first root element, if it is <a> than <xsl:output> is
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
else
<xsl:output method="xml" encoding="us-ascii" indent="no"/>
Thanks in advance.
Well, XSLT is XML so you can of course use XSLT to create another XSLT with the desired output encoding and you can then run it in a separate step.
As an alternative you could check the root element not being an a element and then delegate outputting to xsl:result-document where you can change the encoding:
<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:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="document-node()[*[not(self::a)]]">
<xsl:result-document encoding="US-ASCII">
<xsl:apply-templates/>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/3Nqn5Y8

XSLT- Pre Define NameSpace

Hi I have an XML that upon each delivery has a different unique named Namespace that I cannot pre determine with standard processes.
<ABC xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>111</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>222</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extention>
</Extentions>
</ABC>
The Next XML delivered could be
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extention>
</Extentions>
</ABC>
My current XSL stylesheet works on the first XML predefining the Namespace
But I am looking to find a way to re-define it later on. on the process. I have added a variable to pull the relevant uuid from the Identification element but am not sure how to integrate this. Using the below stylesheet to process any other XML results in false results.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:variable name="SelOpGroup" select="/ABC/Extensions/Identification"/>
<!-- Pass thru --->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/ABC/Extensions/SrcPackage>
<xsl:copy>
<this:ABDList>
<xsl:copy-of select ="this:ABDList/*"/>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin><xsl:value-of select="somethingelse"/> </this:SubBegin>
</xsl:copy>
</xsl:template>
<xsl:template match="/ABC/Extensions/MatPackage>
<xsl:copy>
<this:ABDList>
<xsl:copy-of select ="this:ABDList/*"/>
<TaggedB>999</TaggedB>
</this:ABDList >
<this:SubBegin><xsl:value-of select="somethingelse"/> </this:SubBegin>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Expected Result
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin>a value</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
<TaggedB>999</TaggedA>
</this:ABDList>
<this:SubBegin>a value</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extention>
</Extentions>
</ABC>
Many thanks,
Adrian
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:variable name="SelOpGroup" select="/ABC/Extensions/Identification"/>
<!-- Pass thru -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Extension/SrcPackage">
<xsl:copy>
<xsl:element name="{'this:ABDList'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:copy-of select ="*[name() = 'this:ABDList']/*"/>
<TaggedA>888</TaggedA>
</xsl:element>
<xsl:element name="{'this:SubBegin'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:value-of select="'somethingelse'"/>
</xsl:element>
</xsl:copy>
</xsl:template>
<xsl:template match="Extension/MatPackage">
<xsl:copy>
<xsl:element name="{'this:ABDList'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:copy-of select ="*[name() = 'this:ABDList']/*"/>
<TaggedB>999</TaggedB>
</xsl:element>
<xsl:element name="{'this:SubBegin'}" namespace="{$SelOpGroup}">
<xsl:copy-of select="/*/namespace::*[name()='this']"/>
<xsl:value-of select="'somethingelse'"/>
</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied on the first provided XML document:
<ABC xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>111</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>222</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extension>
</Extensions>
</ABC>
Produces the wanted, correct result:
<ABC xmlns:this="urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1f15a9-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>111</TaggedValue>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>222</TaggedValue>
<TaggedB>999</TaggedB>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</MatPackage><!-- Stuff -->
</Extension>
</Extensions>
</ABC>
When the same transformation is applied on the second provided XML document:
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
</this:ABDList>
<this:SubBegin>0</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
</this:ABDList>
<this:SubBegin>1</this:SubBegin>
</MatPackage>
<!-- Stuff -->
</Extension>
</Extensions>
</ABC>
Again the wanted, correct result is produced:
<ABC xmlns:this="urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331" version="1.1">
<Extensions>
<Identification>urn:uuid:9b1FFae4-69de-11d2-b6bc-fcab70ff7331</Identification>
<Extension>
<SrcPackage>
<this:ABDList>
<TaggedValue>333</TaggedValue>
<TaggedA>888</TaggedA>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</SrcPackage>
<MatPackage>
<this:ABDList>
<TaggedValue>444</TaggedValue>
<TaggedB>999</TaggedB>
</this:ABDList>
<this:SubBegin>somethingelse</this:SubBegin>
</MatPackage><!-- Stuff -->
</Extension>
</Extensions>
</ABC>
This is bizarre input (what were they smoking?). But since the namespace is only used on one element, ABDList, my approach would be to select the ABDList elements using *:ABDList in XSLT 2.0, or *[local-name()='ABDList'] in XSLT 1.0.
I have an XML that upon each delivery has a different unique named
Namespace
Someone ahead of you obviously does not understand the purpose of having a namespace.
Perhaps this could work for your unfortunate situation:
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="SrcPackage/*/TaggedValue">
<xsl:copy-of select="."/>
<TaggedA>888</TaggedA>
</xsl:template>
<xsl:template match="MatPackage/*/TaggedValue">
<xsl:copy-of select="."/>
<TaggedB>999</TaggedB>
</xsl:template>
</xsl:stylesheet>

Change XML element name using XSLT

I am trying to change XML node name but it doesn't allow me to do so. In my below code I I have two templates 1. Change Node name 2.Create parent node for DocumentReference. Please see my XML and XSLT.
My XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DataArea>
<PurchaseOrder>
<PurchaseOrderLine>
<DocumentReference>
<DocumentID>
<ID>23423</ID>
</DocumentID>
</DocumentReference>
<DocumentReference>
<DocumentID>
<ID>23424</ID>
</DocumentID>
</DocumentReference>
<Item>
<CustomerItemID>
<!-- ArtNr -->
<ID>444</ID>
</CustomerItemID>
</Item>
<Quantity unitCode="PCE">17.3</Quantity>
</PurchaseOrderLine>
</PurchaseOrder>
</DataArea>
Expected Result
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<DataArea>
<PurchaseOrder>
<POL>
<DocumentReference>
<DocumentID>
<ID>23423</ID>
</DocumentID>
</DocumentReference>
<DocumentReference>
<DocumentID>
<ID>23424</ID>
</DocumentID>
</DocumentReference>
<Item>
<CustomerItemID>
<!-- ArtNr -->
<ID>444</ID>
</CustomerItemID>
</Item>
<Quantity unitCode="PCE">17.3</Quantity>
</POL>
</PurchaseOrder>
</DataArea>
My XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="PurchaseOrderLine">
<POL>
<xsl:apply-templates />
</POL>
</xsl:template>
<xsl:template match="PurchaseOrderLine">
<xsl:copy>
<Kiran>
<xsl:apply-templates select="#*|DocumentReference"/>
</Kiran>
<xsl:apply-templates select="#*|Item|Quantity"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Then I think you want the template to look like
<xsl:template match="PurchaseOrderLine">
<POL>
<xsl:apply-templates select="#*"/>
<Kiran>
<xsl:apply-templates select="DocumentReference"/>
</Kiran>
<xsl:apply-templates select="node() except DocumentReference" />
</POL>
</xsl:template>

tagging words using lookup, what's the best approach?

I have some strings I want to test to see if they contain specific words. The words in question are in a lookup node, and if there is a match the word in the string needs to be tagged. I have a script that works almost ok, but I want to know if I'm using the best format, as I believe it's rather resource consuming, and not very foolproof.
Example xml :
<Main>
<NTUS>
<NTU>match</NTU>
<NTU>test</NTU>
</NTUS>
<Folder id="update">
<about>This content is not in a span so we ignore it completely, even if we would have a match</about>
<Title>
<span class="string simple" lang="en">Some test content containing a single match</span>
</Title>
<Content>
<span class="string complex" lang="en">Also keywords in sub elements should <strong>pass the test</strong>, and match.</span>
</Content>
</Folder>
</Main>
My current xslt :
<xsl:param name="units">
<xsl:copy-of select="//NTU"/>
</xsl:param>
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="NTUS"/>
<xsl:template match="text()[ancestor::span]">
<xsl:analyze-string select="." regex="\s+">
<xsl:matching-substring>
<xsl:value-of select="."/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:variable name="theWord" select="."/>
<xsl:choose>
<xsl:when test="$units/*[text()=$theWord]">
<ntu>
<xsl:value-of select="."/>
</ntu>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
results in following :
<Main>
<Folder id="update">
<about>This content is not in a span so we ignore it completely, even if we would have a match</about>
<Title>
<span class="string simple" lang="en">Some <ntu>test</ntu> content containing a single <ntu>match</ntu></span>
</Title>
<Content>
<span class="string complex" lang="en">Also keywords in sub elements should <strong>pass the <ntu>test</ntu></strong>, and match.</span>
</Content>
</Folder>
</Main>
Which is almost ok apart from the last node, as the [match] is at the end of the sentence and therefore not passing the regex. I can adjust it to make it match, but it could become pretty complex then, so i want to know if there are better ways to address this problem.
EDIT : there seems to be a small misbehaviour when you use a comma delimited list (might be on other occasions also, but this one I noticed)...
So for instance following xml
<Main>
<NTUS>
<NTU>OPTION1</NTU>
<NTU>OPTION2</NTU>
<NTU>OPTION3</NTU>
<NTU>OPTION4</NTU>
<NTU>OPTION5</NTU>
</NTUS>
<local xml:lang="en">
<span>Test string containing some comma seperarated lookup values: OPTION1, OPTION2, OPTION3, OPTION4, OPTION5</span>
</local>
Returns following when the script is applied :
<span>Test string containing some comma seperarated lookup values: <ntu>OPTION1</ntu>, OPTION2, <ntu>OPTION3</ntu>, OPTION4, <ntu>OPTION5</ntu></span>
so every second match is skipped. Any idea what is causing this behaviour ?
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:variable name="vPatterns" select=
"string-join(/*/NTUS/*, '|')"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="span//text()">
<xsl:analyze-string select="." regex=
"(^|(\P{{L}})+)({$vPatterns})($|(\P{{L}})+)">
<xsl:non-matching-substring><xsl:value-of select="."/></xsl:non-matching-substring>
<xsl:matching-substring>
<xsl:value-of select="regex-group(1)"/>
<ntu><xsl:value-of select="regex-group(3)"/></ntu>
<xsl:value-of select="regex-group(4)"/>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied to the provided XML document:
<Main>
<NTUS>
<NTU>match</NTU>
<NTU>test</NTU>
</NTUS>
<Folder id="update">
<about>This content is not in a span so we ignore it completely, even if we would have a match</about>
<Title>
<span class="string simple" lang="en">Some test content containing a single match</span>
</Title>
<Content>
<span class="string complex" lang="en">Also keywords in sub elements should <strong>pass the test</strong>, and match.</span>
</Content>
</Folder>
</Main>
the wanted, correct result is produced:
<Main>
<NTUS>
<NTU>match</NTU>
<NTU>test</NTU>
</NTUS>
<Folder id="update">
<about>This content is not in a span so we ignore it completely, even if we would have a match</about>
<Title>
<span class="string simple" lang="en">Some <ntu>test</ntu> content containing a testmatch or a single <ntu>match</ntu></span>
</Title>
<Content>
<span class="string complex" lang="en">Also keywords in sub elements should <strong>pass the <ntu>test</ntu></strong>, and <ntu>match</ntu>.</span>
</Content>
</Folder>
</Main>

Resources