XSL key lookup in second file & replace element - attributes

I have two xml files:
Source.xml
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="fhrs:id" v="111111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="fhrs:id" v="333333"/>
<tag k="addr:postcode" v="YYY YYY"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="fhrs:id" v="555555"/>
<tag v="ZZZ ZZZ"/>
</way>
</osm>
Lookup.xml
<FHRSEstablishment>
<EstablishmentCollection>
<EstablishmentDetail>
<FHRSID>111111</FHRSID>
<PostCode>BA1 111</PostCode>
</EstablishmentDetail>
<EstablishmentDetail>
<FHRSID>333333</FHRSID>
<PostCode>BA2 222</PostCode>
</EstablishmentDetail>
<EstablishmentDetail>
<FHRSID>555555</FHRSID>
<PostCode>BA3 333</PostCode>
</EstablishmentDetail>
</EstablishmentCollection>
</FHRSEstablishment>
I wish to compare them using the corresponding #v value of the k=fhrs:id attribute in source.xml with the FHRSID node value in lookup.xml to produce an amended version of source.xml.
When a match is found, the value of the Postcode node should be copied across to replace the value of the #v attribute for the tag element with the attribute k="addr:postcode".
This is the XSL fille:
<xsl:key name="FHRSID-key" match="FHRSID" use="node()"/>
<xsl:variable name="lookup-doc" select="doc('lookup.xml')"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*/tag[#v and key('FHRSID-key', #v, $lookup-doc)]">
<xsl:copy>
<xsl:attribute name="k">addr:postcode</xsl:attribute>
<xsl:attribute name="v" select="key('FHRSID-key', #v, $lookup-doc)/../PostCode/node()"/>
</xsl:copy>
</xsl:template>
This is the current output
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="addr:postcode" v="BA1 111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="addr:postcode" v="BA2 222"/>
<tag k="addr:postcode" v="YYY YYY"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="addr:postcode" v="BA3 333"/>
<tag k="addr:postcode" v="ZZZ ZZZ"/>
</way>
</osm>
This is the desired ouput:
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="fhrs:id" v="111111"/>
<tag k="addr:postcode" v="BA1 111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="fhrs:id" v="333333"/>
<tag k="addr:postcode" v="BA2 222"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="fhrs:id" v="555555"/>
<tag k="addr:postcode" v="BA3 333"/>
</way>
</osm>
As you can see it's replacing the 'fhrs:id' element with the copied postcode element, instead of the original k="addr:postcode".
Incidental questions:
match="*/tag[#v and key('FHRSID-key', #v, $lookup-doc)]"
Is the first occurrence of #v actually doing anything?
To me, this match appears to be searching all tag elements. If so, how can it be restricted to look just for those with just the k="addr:postcode" attribute.
Any other improvements to be recommended, please feel free.

Changing the code to match on the parent
<xsl:key name="FHRSID-key" match="EstablishmentDetail" use="FHRSID"/>
<xsl:variable name="lookup-doc" select="doc('lookup.xml')"/>
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[tag[#k = 'fhrs:id' and key('FHRSID-key', #v, $lookup-doc)]]">
<xsl:copy>
<xsl:apply-templates select="#* , node() except tag[#k = 'addr:postcode']"/>
<tag k="addr:postcode" v="{key('FHRSID-key', tag[#k = 'fhrs:id']/#v, $lookup-doc)/PostCode}"/>
</xsl:copy>
</xsl:template>
gives
<osm>
<count>
<tag k="total" v="1560"/>
</count>
<node>
<tag k="fhrs:id" v="111111"/>
<tag k="addr:postcode" v="BA1 111"/>
</node>
<node>
<tag k="fhrs:id" v="222222"/>
<tag k="addr:postcode" v="XXX XXX"/>
</node>
<node>
<tag k="fhrs:id" v="333333"/>
<tag k="addr:postcode" v="BA2 222"/>
</node>
<way>
<tag k="fhrs:id" v="444444"/>
</way>
<way>
<tag k="fhrs:id" v="555555"/>
<tag v="ZZZ ZZZ"/>
<tag k="addr:postcode" v="BA3 333"/>
</way>
</osm>
where the only problem seems to be the <tag v="ZZZ ZZZ"/> element. I am not sure which are the criteria to copy or not copy existing content, if you only want to keep the tag k="fhrs:id" then change that last template to
<xsl:template match="*[tag[#k = 'fhrs:id' and key('FHRSID-key', #v, $lookup-doc)]]">
<xsl:copy>
<xsl:apply-templates select="#* , tag[#k = 'fhrs:id']"/>
<tag k="addr:postcode" v="{key('FHRSID-key', tag[#k = 'fhrs:id']/#v, $lookup-doc)/PostCode}"/>
</xsl:copy>
</xsl:template>

Related

appending nodes into xslt array during foreach

I have xml (described below), i want to divide the contetn by the "<eop/>" element
where whenever there is an tag itis a new element.
and save the the content in an global array (for later use)
i have a foreach loop over the xml grouped by eop
but i dont know how to append each group to the global array
this is my xml:
<?xml version="1.0" encoding="UTF-8"?>
<mainBody>
<article_1>
<content>
<p>befre eop
<eop eId="eop_386" />
after oep
</p>
</content>
</article_1>
<article_2>
<content>
<p>point content</p>
</content>
</article_2>
<article_3>
<content>
<p>point content</p>
</content>
</article_3>
<article_4>
<content>
<p>before eop 387<eop eId="eop_387" /> after 387</p>
</content>
</article_4>
<article_5>
<content>
<p> content 5</p>
</content>
</article_5>
<article_6>
<content>
<p> before eop 388<eop eId="eop_388" /> after 388</p>
</content>
</article_6>
<article_7>
<content>
<p>before eop 389<eop eId="eop_389" />
</p>
</content>
</article_7>
</mainBody>
and this part of the xslt:
<xsl:template match="mainBody">
<xsl:for-each-group select="descendant::node()" group-ending-with="eop" >
</xsl:for-each-group>
</xsl:template>
thanks
You can put
<xsl:variable name="groups" as="array(node()*)*">
<xsl:for-each-group select="/mainBody/descendant::node()" group-ending-with="eop">
<xsl:sequence select="array { current-group() }"/>
</xsl:for-each-group>
</xsl:variable>
globally (i.e. as a child of xsl:stylesheet) and that way the variable groups of type sequence of array of nodes should be available in any template.

XSLT 3.0 incremental merge

I have two XSLT workflows: Full (XSLT2) and Incremental (XSLT3).
Below full3.xml is the merge & split result of Full workflow:
<Account>
<metadata>
<_uri>full3.xml</_uri>
<created>2020-11-26T23:16:08.076-07:00</created>
<lastModified>2020-11-26T23:16:08.076-07:00</lastModified>
<merge-lineage>
<merged-uri>lot960151-3.xml</merged-uri>
<merged-uri>lot860150-3.xml</merged-uri>
</merge-lineage>
</metadata>
<accountPersistentID>51b10faa</accountPersistentID>
<accountID>ACC300</accountID>
<accountName>bonafide-3</accountName>
<Item>
<contract>
<amount>
<currency>USD</currency>
<amount>5000000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract>
</Item></Account>
I have subsequent incremental input XMLs to be matched & (if matched) merged; if no match, then transform it as above similar structure.
lot660152-3.xml is the raw document structure. The match & merge criteria are the accountId and accountName
<ContractServicing>
<account id="ACC3">
<accountId>ACC300</accountId>
<accountName>bonafide-3</accountName>
<accountBeneficiary href="party5"/>
<servicingParty href="party6"/>
</account>
<contract>
<amount>
<currency>USD</currency>
<amount>5700000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract></ContractServicing>
The desired results of the Incremental XSLT workflow should be:
lot660152-3.xml is matched and its each contract shall be merged into Item element in full3.xml
(NOTE: _uri is generated during the Full workflow and can be changed during the incremental workflow. But the accountPersistentID generated during the Full workflow shall be untouched. Also lastModified and merged-uri shall be updated if any merge event.
<Account>
<metadata>
<_uri>full3.xml</_uri>
<created>2020-11-26T23:16:08.076-07:00</created>
<lastModified>2020-11-29T00:00:00.000-00:00</lastModified>
<merge-lineage>
<merged-uri>lot960151-3.xml</merged-uri>
<merged-uri>lot860150-3.xml</merged-uri>
<merged-uri>lot660152-3.xml</merged-uri>
</merge-lineage>
</metadata>
<accountPersistentID>51b10faa</accountPersistentID>
<accountID>ACC300</accountID>
<accountName>bonafide-3</accountName>
<Item>
<contract>
<amount>
<currency>USD</currency>
<amount>5000000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>5700000.00</amount>
</amount>
</contract>
<contract>
<amount>
<currency>USD</currency>
<amount>4000000.00</amount>
</amount>
</contract>
</Item>
</Account>
Incremental workflow shall create a new document similar to full3.xml for no-matched raw document.
As it currently stands, I am pleased with Full workflow but I can’t seem to get any line on XSLT3 merge instruction during the Incremental workflow.
My XSLT Incremental workflow
<xsl:template match="/">
<xsl:merge>
<xsl:merge-source name="full" streamable="yes" for-each-source="$full-docs" select="Account">
<xsl:merge-key select="accountID"/>
</xsl:merge-source>
<xsl:merge-source name="incremental" for-each-source="$incre-docs" select="ContractServicing">
<xsl:merge-key select="account/accountId"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="current-merge-group('incremental')/account/accountId = current-merge-group('full')/accountID">
<xsl:apply-templates select="current-merge-group('full')"/>
<xsl:for-each select="current-merge-group('full')/Item">
<xsl:copy-of select="current-merge-group('incremental')/contract"/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-merge-group('incremental')" />
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</xsl:template>
The result is none of the matched incremental contract merged into Item and the no-match document has not been transformed. (This has been resolved by Michael Kay)
Null Pointer
I added some boilerplate:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:mode name="merge-contracts" on-no-match="shallow-copy"/>
<xsl:mode name="unmatched" on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
and then changed the xsl:merge-action to
<xsl:merge-action>
<xsl:choose>
<xsl:when test="current-merge-group('incremental')/account/accountId = current-merge-group('full')/accountID">
<xsl:apply-templates select="current-merge-group('full')" mode="merge-contracts">
<xsl:with-param name="extra" select="current-merge-group('incremental')"
tunnel="yes" as="element(ContractServicing)"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-merge-group('incremental')" mode="unmatched"/>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
so if there's a match, it's processing the main document in mode merge-contracts with the incremental document passed in a tunnel parameter; and if there's no match, it's processing the incremental document in mode "unmatched".
The merged-contracts mode has three template rules:
<xsl:template match="lastModified/text()" mode="merge-contracts">
<xsl:value-of select="current-dateTime()"/>
</xsl:template>
<xsl:template match="merge-lineage" mode="merge-contracts">
<xsl:param name="extra" tunnel="yes" as="element(ContractServicing)"/>
<xsl:copy>
<xsl:copy-of select="*"/>
<merged-uri>{
tokenize($extra/root()/document-uri(),'/')[last()]
}</merged-uri>
</xsl:copy>
</xsl:template>
<xsl:template match="Item" mode="merge-contracts">
<xsl:param name="extra" tunnel="yes" as="element(ContractServicing)"/>
<xsl:copy>
<xsl:copy-of select="*, $extra//contract"/>
</xsl:copy>
</xsl:template>
which might not do everything you want to do, but I think it captures the essence.
Where the incremental document isn't matched, it becomes a very routine transformation which I approximated with:
<xsl:template match="ContractServicing" mode="unmatched">
<xsl:result-document href="unmatched.xml">
<Account>
<metadata>...</metadata>
<accountPersistentID>...</accountPersistentID>
<xsl:copy-of select="//contract"/>
</Account>
</xsl:result-document>
</xsl:template>
I'm not really sure where your difficulties arose. Your code refers to an "item" element that doesn't exist; and you didn't show us any code for combining the merge-lineage element or for merging the contracts. I don't know if that's because you had no problems with this code, or because you didn't know how to go about writing it.

Quetion about the xsl:template returning a xsl:map

I know that "Cannot add a map to an XML tree", especially take the xsl:map as result document.
But if I assign a xsl:template to a variable, it can take a xsl:map as result of the xsl:template. For example:
<?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"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="xs"
version="3.0">
<xsl:template match="/">
<xsl:variable name="m1" as="map(*)">
<xsl:call-template name="tmap1"/>
</xsl:variable>
<xsl:variable name="m2" as="map(*)">
<xsl:call-template name="tmap2"/>
</xsl:variable>
</xsl:template>
<xsl:template name="tmap1">
<xsl:sequence select="map{1:'abc', 2:'ccd'}"/>
</xsl:template>
<xsl:template name="tmap2" as="map(*)">
<xsl:map>
<xsl:map-entry key="'Mo'" select="'Monday'"/>
<xsl:map-entry key="'Tu'" select="'Tuesday'"/>
<xsl:map-entry key="'We'" select="'Wednesday'"/>
<xsl:map-entry key="'Th'" select="'Thursday'"/>
<xsl:map-entry key="'Fr'" select="'Friday'"/>
<xsl:map-entry key="'Sa'" select="'Saturday'"/>
<xsl:map-entry key="'Su'" select="'Sunday'"/>
<xsl:map-entry key="'z2'" select="'day'"/>
</xsl:map>
</xsl:template>
These will run well. But I has an error with my work code, and I make a minimum but complete demo to reproduce it.
the code:
<?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"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:rel="http://schemas.openxmlformats.org/package/2006/relationships"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:map = "http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="xs w rel r map v"
version="3.0">
<xsl:template match="/">
<xsl:apply-templates select="w:document/w:body/w:p"/>
</xsl:template>
<xsl:template match="w:p">
<xsl:element name="p">
<xsl:variable name="p_css" as="map(*)*">
<xsl:if test="w:pPr">
<xsl:variable name="t">
<xsl:apply-templates select="w:pPr" mode="style_item"/>
</xsl:variable>
<xsl:if test="not($t instance of map(*))">
<xsl:message>error</xsl:message>
</xsl:if>
</xsl:if>
</xsl:variable>
<xsl:if test="not(empty($p_css))">
<xsl:where-populated>
<xsl:attribute name="style" select="$p_css?2"/>
</xsl:where-populated>
</xsl:if>
<xsl:apply-templates select="w:t"/>
</xsl:element>
</xsl:template>
<xsl:template match="w:pPr" mode="style_item" as="map(*)*">
<xsl:sequence select="map{1:'hi', 2:'hello', 3:'world'}"/>
</xsl:template>
</xsl:stylesheet>
the source document:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" mc:Ignorable="w14 wp14">
<w:body>
<w:p w:rsidR="00F708CA" w:rsidRDefault="00F708CA" w:rsidP="006E4E72">
<w:pPr>
<w:outlineLvl w:val="0"/>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
</w:rPr>
<w:t>你好,大家好。</w:t>
</w:r>
<w:bookmarkStart w:id="0" w:name="_GoBack"/>
<w:bookmarkEnd w:id="0"/>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="Normal"/>
<w:rPr>
<w:b/>
<w:b/>
<w:bCs/>
<w:color w:val="C9211E"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="C9211E"/>
</w:rPr>
<w:t xml:space="preserve">12345good day. </w:t>
</w:r>
</w:p>
<w:p>
<w:pPr>
<w:pStyle w:val="Normal"/>
<w:rPr>
<w:i/>
<w:i/>
<w:iCs/>
<w:color w:val="77BC65"/>
<w:sz w:val="28"/>
<w:szCs w:val="28"/>
<w:highlight w:val="yellow"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:i/>
<w:iCs/>
<w:color w:val="77BC65"/>
<w:sz w:val="28"/>
<w:szCs w:val="28"/>
<w:highlight w:val="yellow"/>
</w:rPr>
<w:t>64789hello world</w:t>
</w:r>
</w:p>
<w:sectPr>
<w:type w:val="nextPage"/>
<w:pgSz w:w="11906" w:h="16838"/>
<w:pgMar w:left="1134" w:right="1134" w:header="0" w:top="1134" w:footer="0"
w:bottom="1134" w:gutter="0"/>
<w:pgNumType w:fmt="decimal"/>
<w:formProt w:val="false"/>
<w:textDirection w:val="lrTb"/>
</w:sectPr>
</w:body>
</w:document>
The error displays "Cannot add a map to an XML tree" when runtime,
my xslt proccessor is saxon-he 9.8.0.12
If you want a result (principal or secondary) to show/serialize a map then use the output method adaptive (or json if the map represents JSON) for that result:
<xsl:output method="adaptive" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="m1" as="map(*)">
<xsl:call-template name="tmap1"/>
</xsl:variable>
<xsl:variable name="m2" as="map(*)">
<xsl:call-template name="tmap2"/>
</xsl:variable>
<xsl:sequence select="$m1, $m2"/>
</xsl:template>
https://xsltfiddle.liberty-development.net/gWEamLu
<xsl:output method="json" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="m1" as="map(*)">
<xsl:call-template name="tmap1"/>
</xsl:variable>
<xsl:variable name="m2" as="map(*)">
<xsl:call-template name="tmap2"/>
</xsl:variable>
<xsl:sequence select="[$m1, $m2]"/>
</xsl:template>
https://xsltfiddle.liberty-development.net/gWEamLu/1
My problem is that the '<xsl:variable name="t">' variable don't have a explicit type declaration.

Matching strings inside <![CDATA]>

I have a DMN document that is using <![CDATA["text"]]> to represent string values. I am trying to all the words in an input string against one of the strings in these CDATA sections but I cannot figure out which XPath expression will do the trick.
Here is a sample DMN file:
<definitions xmlns="http://www.omg.org/spec/DMN/20151101/dmn.xsd" id="definitions_0fyde0d"
name="definitions" namespace="http://camunda.org/schema/1.0/dmn">
<decision id="decision" name="TroubleArea">
<decisionTable id="decisionTable">
<input id="input1" label="UserText">
<inputExpression id="inputExpression1" typeRef="string">
<text/>
</inputExpression>
</input>
<output id="output1" label="Subsystem" name="" typeRef="string"/>
<rule id="row-22012340-2">
<inputEntry id="UnaryTests_1hacpom">
<text><![CDATA["signal", "input", "connection"]]></text>
</inputEntry>
<outputEntry id="LiteralExpression_0wvuvyc">
<text><![CDATA["input"]]></text>
</outputEntry>
</rule>
<rule id="row-22012340-3">
<inputEntry id="UnaryTests_0cmpu76">
<text><![CDATA["screen"]]></text>
</inputEntry>
<outputEntry id="LiteralExpression_0hkc81e">
<text><![CDATA["output"]]></text>
</outputEntry>
</rule>
</decisionTable>
</decision>
The input is a single string, which needs to be matched against any string between quotes in the CDATA sections of <inputEntry> elements. When the match is found, I need to return the string in the <outputEntry> of the same <rule>.
After adding the namespace into my XSL, I can match the <decisionTable>, but I am still not getting any matches on any of the strings. Here is the code I am using to check if there are matches at all. This is not getting the <outputEntry> string yet, just "Yes" or "No" to tell me if there is a match at all.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:param name="input"/>
<xsl:template match="/">
<result>
<xsl:variable name="table">
<xsl:value-of select="//dmn:decisionTable"/>
</xsl:variable>
<xsl:for-each select="distinct-values(tokenize($input,'%20'))">
<item>
<xsl:value-of select="."/>
<xsl:text>: </xsl:text>
<xsl:call-template name="matchrule">
<xsl:with-param name="text">
<xsl:value-of select="concat('"',.,'"')"/>
</xsl:with-param>
<xsl:with-param name="table">
<xsl:value-of select="$table"/>
</xsl:with-param>
</xsl:call-template>
</item>
</xsl:for-each>
</result>
</xsl:template>
<xsl:template name="matchrule">
<xsl:param name="table"/>
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="$table//dmn:rule[contains(dmn:inputEntry/dmn:text,$text)]">
<xsl:text>Yes</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>No</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Testing this with the input string "something%20with%20the%20screen%20or%20the%20screen%20brightness" gives the result:
result xmlns:dmn="http://www.omg.org/spec/DMN/20151101/dmn.xsd">
<item>something: No</item>
<item>with: No</item>
<item>the: No</item>
<item>screen: No</item>
<item>or: No</item>
<item>brightness: No</item>
I cannot change the DMN to not use those <![CDATA]> entries, as the table is created by another tool that I have no control over.
I think one way is to use
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://www.omg.org/spec/DMN/20151101/dmn.xsd"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:param name="input">something%20with%20the%20screen%20or%20the%20screen%20brightness</xsl:param>
<xsl:template match="/">
<result>
<xsl:variable name="rules" select="//rule"/>
<xsl:for-each select="distinct-values(tokenize($input,'%20'))">
<item>
<xsl:value-of select="."/>
<xsl:text>: </xsl:text>
<xsl:apply-templates select="$rules[inputEntry/text[contains(., concat('"', current(), '"'))]]"/>
</item>
</xsl:for-each>
</result>
</xsl:template>
<xsl:template match="rule">
<xsl:value-of select="outputEntry/text"/>
</xsl:template>
</xsl:stylesheet>
which outputs
<result>
<item>something: </item>
<item>with: </item>
<item>the: </item>
<item>screen: "output"</item>
<item>or: </item>
<item>brightness: </item>
</result>
Online sample http://xsltransform.net/gVhD8RW.

Replacing one namespace with another

In the below input XML I am getting ns1 and ns2 prefixes.
In the output the namespace ns1 should be replaced with dh and the namespace ns2 should be replaced with sk.
Can anyone please help on this.
<?xml version="1.0" encoding="UTF-8" ?>
<sh:sampleDocument schemaVersion="" creationDate=""xmlns:sh="htpp://sample1.com">
<sampleHeader>
<ns1:sampledocumentheader xmlns:ns1="htpp://sample2.com">
<ns1:HeaderVersion />
<ns1:ContactInformation>
<ns1:Contact />
<ns1:EmailAddress />
<ns1:FaxNumber />
<ns1:TelephoneNumber />
<ns1:ContactTypeIdentifier />
</ns1:ContactInformation>
</ns1:sampledocumentheader>
</sampleHeader>
<sampleBody>
<sampleList>
<sampleEvent>
<Time />
<action />
<ns2:sampleExtension xmlns:ns2="htpp://sample3.com">
<ns2:Value />
<ns2:Number />
</ns2:sampleExtension>
</sampleEvent>
</sampleList>
</sampleBody>
</sh:sampleDocument>
There should be no need to do this. The choice of a namespace prefix is completely arbitrary. If the target application requires a specific prefix to be used, then it's the target application that needs to be fixed, not your XML.
Anyway, try:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="htpp://sample2.com"
xmlns:ns2="htpp://sample3.com"
exclude-result-prefixes="ns1 ns2">
<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="ns1:*">
<xsl:element name="dh:{local-name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="ns2:*">
<xsl:element name="sk:{local-name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Resources