How do I fix this XSLT that stopped working? - xslt-2.0

I have this XSLT that Marting Honnen graciously supplied (link)
The template stopped working for some reason and I can't seem to fix it. The data expanded but I don't see how that should matter.
Instead of turning the double pipe delimited text into xml; it just deletes the delimited data
Here's the template and sample data:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="str">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:analyze-string select="." regex="\|((\|[^|]+\|)+)\|">
<xsl:matching-substring>
<xsl:analyze-string select="regex-group(1)" regex="\|(\w+):([^|]+)\|">
<xsl:matching-substring>
<xsl:element name="{regex-group(1)}">
<xsl:value-of select="regex-group(2)"/>
</xsl:element>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
data before: (note the data has expanded)
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1 stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname ||phone:3282||email:Lori.KS#.edu||officenumber:D-107A||vcard:https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b||photo:https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846||pronunciation:https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846|| background:n/a || experience:n/a || divisiongroup:11-80 || groupdesc:TII || tags:n/a || </str>
</arr>
</doc>
Can I use XSLT to transform this XML into this?
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1 stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname
<phone>3282</phone>
<email>Lori.KS#.edu</email>
<officenumber>D-107A</officenumber>
<vcard>https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b</vcard>
<photo>https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</photo>
<pronunciation>https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</pronunciation>
<background> ...
</str>
</arr>
</doc>

Some of your colon separated fields have leading and trailing white space (e.g. | background:n/a |) so the regular expressions needs some tuning:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="str">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:analyze-string select="." regex="\|((\|\s*[^|]+\s*\|)+)\|">
<xsl:matching-substring>
<xsl:analyze-string select="regex-group(1)" regex="\|\s*(\w+):([^|]+?)\s*\|">
<xsl:matching-substring>
<xsl:element name="{regex-group(1)}">
<xsl:value-of select="regex-group(2)"/>
</xsl:element>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Using that stylesheet on your posted input Saxon 9.5 outputs
<doc>
<arr name="content">
<str> stream_source_info docname stream_content_type text/html stream_size 412 Content-Encoding ISO-8859-1
stream_name docname Content-Type text/html; charset=ISO-8859-1 resourceName docname <phone>3282</phone>
<email>Lori.KS#.edu</email>
<officenumber>D-107A</officenumber>
<vcard>https://c3qa/profiles/vcard/profile.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b</vcard>
<photo>https://c3qa/profiles/photo.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</photo>
<pronunciation>https://c3qa/profiles/audio.do?key=5c28d263-d8aa-4a8a-ae90-4e8b13de7a0b&lastMod=1348674215846</pronunciation>
<background>n/a</background>
<experience>n/a</experience>
<divisiongroup>11-80</divisiongroup>
<groupdesc>TII</groupdesc>
<tags>n/a</tags>
</str>
</arr>
</doc>

Related

How can grouped the TEXT/ELEMENT by xsl:for-each-group element in XSLT 2.0

INPUT XML:
<overline-start id="tie1" specific-use="tie-bar"/>PtCl<sub>2</sub>(P((CH<sub>2</sub>)<sub><italic toggle="yes">n</italic></sub>)<sub>3</sub><overline-end rid="tie1"/>
EXPECTED XML:
<overline id="tie1" specific-use="tie-bar">PtCl<sub>2</sub>(P((CH<sub>2</sub>)<sub><italic toggle="yes">n</italic></sub>)<sub>3</sub></overline>
MY XSLT 2.0 Code:
<xsl:template match="overline-start">
<xsl:for-each-group select="self::overline-start" group-adjacent="self::overline-start[following-sibling::overline-end]">
<xsl:for-each select="current-group()">
<overline>
<xsl:apply-templates select="#*"/>
<xsl:copy-of select="current-group()"/>
</overline>
</xsl:for-each>
As you mentioned the requirement in comments, I tried it #Martin Honnen 's way:
Assuming input as:
<?xml version="1.0" encoding="UTF-8"?>
<p>
<overline-start id="tie1" specific-use="tie-bar"/>PtCl<sub>2</sub>(P((CH<sub>2</sub>)<sub><italic toggle="yes">n</italic></sub>)<sub>3</sub><overline-end rid="tie1"/>
</p>
A 2.0 solution can be:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="no" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<overline>
<xsl:for-each-group select="* | text()" group-starting-with="overline-start">
<xsl:for-each-group select="current-group()" group-ending-with="overline-end">
<xsl:apply-templates select="#*" />
<xsl:sequence select="(current-group() except .) [position() != last()]" />
</xsl:for-each-group>
</xsl:for-each-group>
</overline>
</xsl:template>
</xsl:stylesheet>
http://xsltfiddle.liberty-development.net/bnnZW8/1

change the xlmns value without modifying the prefix using xslt (with built in templates)

Source XML Document:
<?xml version="1.0" encoding="UTF-8"?>
<PREMIS:premis xmlns:PREMIS="info:lc/xmlns/premis-v2" version="2.2">
<PREMIS:object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="PREMIS:file">
<PREMIS:objectIdentifier>
<PREMIS:objectIdentifierType>Docuteam</PREMIS:objectIdentifierType>
<PREMIS:objectIdentifierValue>_20161027171024801</PREMIS:objectIdentifierValue>
</PREMIS:objectIdentifier>
<PREMIS:objectCharacteristics>
<PREMIS:compositionLevel>0</PREMIS:compositionLevel>
<PREMIS:fixity>
<PREMIS:messageDigestAlgorithm>SHA-512</PREMIS:messageDigestAlgorithm>
<PREMIS:messageDigest>2b9be7ebeae4135b0002cfcd7ee4ee2f5d93e80bfabebf6d5d409e504ad1cbd920487f56726362c2a2979b68d96b1c26f37a73e68c30dd9f8cf11502c634ff5a</PREMIS:messageDigest>
</PREMIS:fixity>
<PREMIS:size>32783388</PREMIS:size>
<PREMIS:format>
<PREMIS:formatDesignation>
<PREMIS:formatName>Tagged Image File Format</PREMIS:formatName>
</PREMIS:formatDesignation>
<PREMIS:formatRegistry>
<PREMIS:formatRegistryName>PRONOM</PREMIS:formatRegistryName>
<PREMIS:formatRegistryKey>fmt/353</PREMIS:formatRegistryKey>
</PREMIS:formatRegistry>
</PREMIS:format>
</PREMIS:objectCharacteristics>
<PREMIS:originalName xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple"
>12448399.tif</PREMIS:originalName>
</PREMIS:object>
<PREMIS:event>
<PREMIS:eventIdentifier>
<PREMIS:eventIdentifierType>Docuteam</PREMIS:eventIdentifierType>
<PREMIS:eventIdentifierValue>_20161027171025082</PREMIS:eventIdentifierValue>
</PREMIS:eventIdentifier>
<PREMIS:eventType>Creation</PREMIS:eventType>
<PREMIS:eventDateTime>2016-10-27T17:10:25</PREMIS:eventDateTime>
<PREMIS:eventDetail>Performed by: &apos;INGEST-01$&apos;</PREMIS:eventDetail>
<PREMIS:eventOutcomeInformation>
<PREMIS:eventOutcome>Success</PREMIS:eventOutcome>
</PREMIS:eventOutcomeInformation>
<PREMIS:linkingObjectIdentifier xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:type="simple">
<PREMIS:linkingObjectIdentifierType>Docuteam</PREMIS:linkingObjectIdentifierType>
<PREMIS:linkingObjectIdentifierValue>_20161027171024801</PREMIS:linkingObjectIdentifierValue>
</PREMIS:linkingObjectIdentifier>
</PREMIS:event>
<PREMIS:event>
<PREMIS:eventIdentifier>
<PREMIS:eventIdentifierType>Docuteam</PREMIS:eventIdentifierType>
<PREMIS:eventIdentifierValue>_20161027171031973</PREMIS:eventIdentifierValue>
</PREMIS:eventIdentifier>
<PREMIS:eventType>Fixity Check</PREMIS:eventType>
<PREMIS:eventDateTime>2016-10-27T17:10:31</PREMIS:eventDateTime>
<PREMIS:eventDetail>Based on sa_ub-erara-01_dss-01. Performed by:
&apos;INGEST-01$&apos;</PREMIS:eventDetail>
<PREMIS:eventOutcomeInformation>
<PREMIS:eventOutcome>Success</PREMIS:eventOutcome>
</PREMIS:eventOutcomeInformation>
<PREMIS:linkingObjectIdentifier xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:type="simple">
<PREMIS:linkingObjectIdentifierType>Docuteam</PREMIS:linkingObjectIdentifierType>
<PREMIS:linkingObjectIdentifierValue>_20161027171024801</PREMIS:linkingObjectIdentifierValue>
</PREMIS:linkingObjectIdentifier>
</PREMIS:event>
</PREMIS:premis>
My XSLT:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:PREMIS="info:lc/xmlns/premis-v2"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple"
>
<xsl:output method="xml"/>
<xsl:template match="/">
<rdf:RDF>
<xsl:value-of select="'
'"/>
<xsl:value-of select="'
'"/>
<xsl:apply-templates/>
</rdf:RDF>
</xsl:template>
<xsl:template match="PREMIS:premis">
<xsl:apply-templates select="PREMIS:object"/>
<xsl:value-of select="'
'"/>
<xsl:apply-templates select="PREMIS:event"/>
<xsl:value-of select="'
'"/>
</xsl:template>
<xsl:template match="PREMIS:object">
<!-- Verknüpfung zwischen Fedora- und PREMIS-Objekt -->
<!-- Der Identifikator des Fedoraobjektes "info:fedora/CH-001898-1:X" ist nicht im PREMIS-XML gespeichert, sondern muss irgendwie extern eingefügt werden -->
<rdf:Description rdf:about="info:fedora/CH-001898-1:7">
<PREMIS:hasObject><xsl:value-of select="PREMIS:objectIdentifier/PREMIS:objectIdentifierValue"/></PREMIS:hasObject>
</rdf:Description>
<xsl:value-of select="'
'"/>
<!-- PREMIS:object -->
<!-- Ebene1 -->
<rdf:Description>
<xsl:attribute name="rdf:about">
<xsl:value-of select="PREMIS:objectIdentifier/PREMIS:objectIdentifierValue"/>
</xsl:attribute>
<PREMIS:hasIdentifier><xsl:value-of select="PREMIS:objectIdentifier/PREMIS:objectIdentifierValue"/><xsl:text>objectIdentifier</xsl:text></PREMIS:hasIdentifier>
<PREMIS:hasOriginalName><xsl:value-of select="PREMIS:originalName"/></PREMIS:hasOriginalName>
</rdf:Description>
<xsl:value-of select="'
'"/>
<!-- Ebene2 -->
<rdf:Description>
<xsl:attribute name="rdf:about">
<xsl:value-of select="PREMIS:objectIdentifier/PREMIS:objectIdentifierValue"/><xsl:text>objectIdentifier</xsl:text></xsl:attribute>
<PREMIS:hasIdentifierType><xsl:value-of select="PREMIS:objectIdentifier/PREMIS:objectIdentifierType"/></PREMIS:hasIdentifierType>
<PREMIS:hasIdentifierValue><xsl:value-of select="PREMIS:objectIdentifier/PREMIS:objectIdentifierValue"/></PREMIS:hasIdentifierValue>
</rdf:Description>
<xsl:value-of select="'
'"/>
</xsl:template>
<!-- Events -->
<!-- Ebene1 -->
<xsl:template match="PREMIS:event">
<rdf:Description>
<xsl:attribute name="rdf:about">
<xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/></xsl:attribute>
<PREMIS:hasIdentifier><xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/></PREMIS:hasIdentifier>
<PREMIS:EventDateTime><xsl:value-of select="PREMIS:eventDateTime"/></PREMIS:EventDateTime>
<PREMIS:EventDetail><xsl:value-of select="PREMIS:eventDetail"/></PREMIS:EventDetail>
<PREMIS:hasEventOutcomeInformation><xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/><xsl:text>eventOutcomeInformation</xsl:text></PREMIS:hasEventOutcomeInformation>
<PREMIS:hasEventLinkingObjectIdentifier><xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/><xsl:text>eventLinkingObjectIdentifier</xsl:text></PREMIS:hasEventLinkingObjectIdentifier>
</rdf:Description>
<xsl:value-of select="'
'"/>
<!-- Ebene2 -->
<rdf:Description>
<xsl:attribute name="rdf:about">
<xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/><xsl:text>eventIdentifier</xsl:text></xsl:attribute>
<PREMIS:hasIdentifierType><xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierType"/></PREMIS:hasIdentifierType>
<PREMIS:hasIdentifierValue><xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/></PREMIS:hasIdentifierValue>
</rdf:Description>
<xsl:value-of select="'
'"/>
<rdf:Description>
<xsl:attribute name="rdf:about">
<xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/><xsl:text>eventOutcomeInformation</xsl:text></xsl:attribute>
<PREMIS:hasEventOutcome><xsl:value-of select="PREMIS:eventOutcomeInformation/PREMIS:eventOutcome"/></PREMIS:hasEventOutcome>
</rdf:Description>
<xsl:value-of select="'
'"/>
<rdf:Description>
<xsl:attribute name="rdf:about">
<xsl:value-of select="PREMIS:eventIdentifier/PREMIS:eventIdentifierValue"/><xsl:text>eventLinkingObjectIdentifier</xsl:text></xsl:attribute>
<PREMIS:linkingObjectIdentifierType><xsl:value-of select="PREMIS:linkingObjectIdentifier/PREMIS:linkingObjectIdentifierType"/></PREMIS:linkingObjectIdentifierType>
<PREMIS:hasLinkingObjectIdentifierValue><xsl:value-of select="PREMIS:linkingObjectIdentifier/PREMIS:linkingObjectIdentifierValue"/></PREMIS:hasLinkingObjectIdentifierValue>
</rdf:Description>
<xsl:value-of select="'
'"/>
</xsl:template>
</xsl:stylesheet>
In the output xml document I want the value of xmlns:PREMIS to be changed to "http://www.loc.gov/premis/rdf/v1#". So the opening root element should look like this:
<rdf:RDF xmlns:PREMIS="info:lc/xmlns/premis-v2"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xlink="http://www.w3.org/1999/xlink">
I've tried several things, also posts I've discovered in here. But I don't get it. Any ideas? Thanks.
Post-Process XSLT:
<?xml version="1.0"?>
<!-- sample_2.xsl -->
<xsl:stylesheet version="2.0"
exclude-result-prefixes="PREMIS"
xmlns:PREMIS="info:lc/xmlns/premis-v2"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple"
>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="namespace::* except namespace::PREMIS"/>
<xsl:namespace name="PREMIS" select="'http://www.loc.gov/premis/rdf/v1#'"/>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="PREMIS:*">
<xsl:element name="PREMIS:{local-name()}" namespace="http://www.loc.gov/premis/rdf/v1#">
<xsl:copy-of select="namespace::* except namespace::PREMIS"/>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template></xsl:stylesheet>
I'm assuming that your desired output is a typo, and that you actually want this:
<rdf:RDF xmlns:PREMIS="http://www.loc.gov/premis/rdf/v1#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xlink="http://www.w3.org/1999/xlink">
...
</rdf:RDF>
In your stylesheet, using the same prefix PREMIS to refer to different namespaces depending on whether you are reading or writing is going to be extremely difficult. Does the prefix in the output really have to be PREMIS, or will some other prefix do? If it does have to be the same (and perhaps anyway) I think my preferred approach would be to post-process the output using:
<xsl:stylesheet exclude-result-prefixes="PREMIS"...>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="namespace::* except namespace::PREMIS"/>
<xsl:namespace name="PREMIS" select="'http://www.loc.gov/premis/rdf/v1#'"/>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="PREMIS:*">
<xsl:element name="PREMIS:{local-name()}" namespace="http://www.loc.gov/premis/rdf/v1#">
<xsl:copy-of select="namespace::* except namespace::PREMIS"/>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>

Extracting value from External xml based on some rule in xsl

This is input xml input.xml
<root>
<bodytext>
<remotelink refptid="HKBL1.0001.lohk.CAP65">some text</remotelink>
<remotelink refptid="HKBL1.0001.lohk.CAP199999">some text</remotelink>
</bodytext>
</root>
This is Prop.xml
<?xml version="1.0" encoding="utf-8"?>
<properties>
<code dpsi="0BZG" docid="asdww">HKBL1.0001.lohk.CAP65</code>
<code dpsi="0BZH" docid="navin">HKBL1.0002.aohk.CAP383</code>
<code no="3">345</code>
</properties>
This is desired output
<root>
<bodytext>
<remotelink refptid="HKBL1.0001.lohk.CAP65" dpsi="0BZG" docid="asdww">some text</remotelink>
<remotelink refptid="HKBL1.0001.lohk.CAP199999">some text</remotelink>
</bodytext>
</root>
IF prop.xml code/text matches remotelink/#refptid than copy attribute of prop.xml to remotelink otherwise no changes in remotelink.
This is the XSLT I have written. So far I am not getting result for unmatched condition:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlsx="http://www.stylusstudio.com/XSLT/XLSX" xmlns:spml="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:saxon="http://saxon.sf.net/" version="2.0">
<xsl:template match="#*|node()" name="root">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="remotelink[#service='DOC-ID']" name="t-remote">
<xsl:variable name="refptid" select="./#refpt"/>
<xsl:variable name="path" select="doc('file:/C:/Users/DalalNS/Desktop/xslt/prop.xml')"/>
<xsl:for-each select="$path/properties/code">
<xsl:choose>
<xsl:when test="./text()=$refptid">
<xsl:element name="remotelink">
<xsl:attribute name="DOC-ID" select="./#docid"/>
<xsl:attribute name="dpsi" select="./#dpsi"/>
<xsl:attribute name="refpt" select="$refptid"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:if test="./#docrefid"/>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="remotelink[#service='DOC-ID']"> will never never be triggered, there's no service attribute on the <remotelink> element. Moreover, you don't retrieve the correct attribute (refpt instead of refptid)
This XSL transformation should do the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlsx="http://www.stylusstudio.com/XSLT/XLSX" xmlns:spml="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:saxon="http://saxon.sf.net/" version="2.0">
<xsl:variable name="props.doc" select="doc('file:/C:/Users/DalalNS/Desktop/xslt/prop.xml')/properties" />
<xsl:template match="#*|node()" name="root">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="remotelink" name="t-remote">
<xsl:variable name="refptid" select="./#refptid"/>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:if test="$props.doc/code[. = $refptid]">
<xsl:apply-templates select="$props.doc/code[. = $refptid]/#*"/>
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This is the result of the transformation:
<?xml version="1.0" encoding="UTF-8"?><root>
<bodytext>
<remotelink refptid="HKBL1.0001.lohk.CAP65" dpsi="0BZG" docid="asdww">some text</remotelink>
<remotelink refptid="HKBL1.0001.lohk.CAP199999">some text</remotelink>
</bodytext>
</root>
I would simply define a global parameter or variable <xsl:variable name="path" select="doc('file:/C:/Users/DalalNS/Desktop/xslt/prop.xml')"/>, then set up a key <xsl:key name="prop" match="code" use="."/>, and then use that in a template
<xsl:template match="remotelink[key('prop', #refptid, $path)]">
<xsl:copy>
<xsl:copy-of select="key('prop', #refptid, $path)/#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
that, together with your first template, should suffice.

limiting variable with names to 127 chars, keeping whole names

I have this xml:
<Artists>
<Name>Name1</Name>
<Name>Name2</Name>
<Name>Name3</Name>
<Name>Name4</Name>
<Name>Name5</Name>
...
<Name>Namex</Name>
</Artists>
I don't know how long the list is.
And I want to end up with something like:
<Limit_Artists>Name1; Name2; Name3; Name4; Name5; Name(n)</Limit_Artists>
But where the total length of must not exeed 127 chars and the last name must not "be split" in the middle. In other words I just need as many whole names from the top of the list, that fits within 127 chars.
I can put the names in a variable all together. but how can I stop before 127 chars?
best regards..
Not efficient but
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '')) le 127]" separator="; "/>
</Limit_Artists>
</xsl:template>
should do.
A complete example is
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '')) le $limit]" separator="; "/>
</Limit_Artists>
</xsl:template>
</xsl:stylesheet>
Note that the code counts only the contents of Name elements but outputs them concatenated by ; so the output could that way be longer than 127. If you want to restrict the output to 127 characters then you have to change the string-join call to use
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '; ')) le 127]" separator="; "/>
</Limit_Artists>
</xsl:template>
respectively the full example to
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '; ')) le $limit]" separator="; "/>
</Limit_Artists>
</xsl:template>
</xsl:stylesheet>
Or you could use sibling recursion along the following sibling axis, collecting the length of items until you hit the length you want to limit the output to. A complete example is
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:apply-templates select="Name[1]">
<xsl:with-param name="limit" select="$limit"/>
</xsl:apply-templates>
</Limit_Artists>
</xsl:template>
<xsl:template match="Artists/Name">
<xsl:param name="limit" as="xs:integer"/>
<xsl:param name="length" as="xs:integer" select="0"/>
<xsl:variable name="new-length" select="$length + string-length()"/>
<xsl:if test="$new-length le $limit">
<xsl:value-of select="if ($length eq 0) then . else concat('; ', .)"/>
<xsl:apply-templates select="following-sibling::Name[1]">
<xsl:with-param name="limit" select="$limit"/>
<xsl:with-param name="length" select="$new-length"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The above sample also only counts the Name characters but concatenates them so it would need to be adapted as well if you want to restrict the output to 127 characters. That could be done as follows:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:param name="sep" as="xs:string" select="'; '"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:apply-templates select="Name[1]">
<xsl:with-param name="limit" select="$limit"/>
</xsl:apply-templates>
</Limit_Artists>
</xsl:template>
<xsl:template match="Artists/Name">
<xsl:param name="limit" as="xs:integer"/>
<xsl:param name="length" as="xs:integer" select="0"/>
<xsl:variable name="new-length" select="if ($length eq 0) then string-length() else $length + string-length($sep) + string-length()"/>
<xsl:if test="$new-length le $limit">
<xsl:value-of select="if ($length eq 0) then . else concat($sep, .)"/>
<xsl:apply-templates select="following-sibling::Name[1]">
<xsl:with-param name="limit" select="$limit"/>
<xsl:with-param name="length" select="$new-length"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Move elements from one place to another using XSLT 2

Move elements from one place to another using XSLT 2 (saxon8)
Hi all please help me to produce the following output using XSLT 2.0.
I have this:
<UL>
<ITEM>
aaa
<NL>iii
<ITEM1>111</ITEM1>
<ITEM2>222</ITEM2>
</NL>
</ITEM>
<ITEM>
bbb
<NL>vvv
<ITEM1>333</ITEM1>
<ITEM2>444</ITEM2>
</NL>
</ITEM>
</UL>
I need to produce this
<UL>
<ITEM>
aaa
<ITEM1>111</ITEM1>
</ITEM>
<ITEM>
bbb
<ITEM1>333</ITEM1>
</ITEM>
<NEW>
<NL>iii
<ITEM2>222</ITEM2>
</NL>
<NL>vvv
<ITEM2>444</ITEM2>
</NL>
</NEW>
</UL>
I am trying to get the output using mode option as mentioned below:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="NL"/>
<xsl:template match="ITEM2"/>
<xsl:template match="UL">
<xsl:copy>
<xsl:apply-templates/>
<NEW>
<xsl:apply-templates select="descendant::NL" mode="move"/>
</NEW>
</xsl:copy>
</xsl:template>
<xsl:template match="ITEM" mode="move">
<xsl:copy>
<xsl:apply-templates/>
<xsl:apply-templates select="descendant::ITEM2" mode="move1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="NL" mode="move">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="ITEM2" mode="move1">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Thanks and regards
Bala
Here is an XSLT 2.0 stylesheet that creates the structure you want, although white space is different, as it is a problem with mixed content to produce the exact output:
<?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:template match="UL">
<xsl:copy>
<xsl:for-each-group select="ITEM" group-by="NL/*/node-name(.)">
<xsl:choose>
<xsl:when test="position() eq 1">
<xsl:for-each select="current-group()">
<ITEM>
<xsl:apply-templates select="text() | NL/*[node-name(.) eq current-grouping-key()]"/>
</ITEM>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<NEW>
<xsl:for-each select="current-group()">
<NL>
<xsl:apply-templates select="NL/(text() | *[node-name(.) eq current-grouping-key()])"/>
</NL>
</xsl:for-each>
</NEW>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="NL/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I get the result
<UL><ITEM>
aaa
<ITEM1>111</ITEM1>
</ITEM><ITEM>
bbb
<ITEM1>333</ITEM1>
</ITEM><NEW><NL>iii
<ITEM2>222</ITEM2>
</NL><NL>vvv
<ITEM2>444</ITEM2>
</NL></NEW></UL>
When I add instructions to strip white space from the input and indent the output, as in
<?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:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="UL">
<xsl:copy>
<xsl:for-each-group select="ITEM" group-by="NL/*/node-name(.)">
<xsl:choose>
<xsl:when test="position() eq 1">
<xsl:for-each select="current-group()">
<ITEM>
<xsl:apply-templates select="text() | NL/*[node-name(.) eq current-grouping-key()]"/>
</ITEM>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<NEW>
<xsl:for-each select="current-group()">
<NL>
<xsl:apply-templates select="NL/(text() | *[node-name(.) eq current-grouping-key()])"/>
</NL>
</xsl:for-each>
</NEW>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="NL/*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
the result is
<UL>
<ITEM>
aaa
<ITEM1>111</ITEM1>
</ITEM>
<ITEM>
bbb
<ITEM1>333</ITEM1>
</ITEM>
<NEW>
<NL>iii
<ITEM2>222</ITEM2>
</NL>
<NL>vvv
<ITEM2>444</ITEM2>
</NL>
</NEW>
</UL>
As an alternative, if we know there are just ITEM1 and ITEM2 we want to split, here is stylesheet using modes:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()" mode="#all">
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="NL">
<xsl:apply-templates select="ITEM1"/>
</xsl:template>
<xsl:template match="ITEM2"/>
<xsl:template match="UL">
<xsl:copy>
<xsl:apply-templates/>
<NEW>
<xsl:apply-templates select="descendant::NL" mode="move"/>
</NEW>
</xsl:copy>
</xsl:template>
<xsl:template match="ITEM1" mode="move"/>
</xsl:stylesheet>

Resources