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

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>

Related

Aggregate nodes based on conditon under new parent

I have an given XML and I want to convert it in new xml and want to aggregate nodes based on status and orderId.
<?xml version="1.0" encoding="utf-8"?>
<OrderStatusUpdate>
<OrderStatusEvents>
<OrderStatusEvent>
<StoreCode>store1</StoreCode>
<OrderId>Order1</OrderId>
<ItemId>Item1</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:37:05</OrderStatusEventTimeStamp>
<StatusName>Cancelled</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
<OrderStatusEvent>
<StoreCode>Store1</StoreCode>
<OrderId>Order1</OrderId>
<ItemId>Item2</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:48:35</OrderStatusEventTimeStamp>
<StatusName>Cancelled</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
<OrderStatusEvent>
<StoreCode>Store1</StoreCode>
<OrderId>Order1</OrderId>
<ItemId>Item3</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:48:35</OrderStatusEventTimeStamp>
<StatusName>Shipped</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
<OrderStatusEvent>
<StoreCode>Store1</StoreCode>
<OrderId>Order2</OrderId>
<ItemId>Item1</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:48:35</OrderStatusEventTimeStamp>
<StatusName>Cancelled</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
</OrderStatusEvents>
</OrderStatusUpdate>
And I want an output like this. Here I am grouping elements based on status and orderId.
<Orders>
<group name="CANCELLED">
<STATUS ID="CANCELLED" DESCRIPTION="Goods Cancelled">
<ORDER ID="Order1">
<ORDER_ITEM item="item1" />
<ORDER_ITEM item="item2" />
</ORDER>
</STATUS>
<STATUS ID="CANCELLED" DESCRIPTION="Goods Cancelled">
<ORDER ID="Order2">
<ORDER_ITEM item="item1" />
</ORDER>
</STATUS>
</group>
<group name="SHIPPED">
<STATUS ID="SHIPPED" DESCRIPTION="Goods SHIPPED">
<ORDER ID="Order1">
<ORDER_ITEM item="item3" />
</ORDER>
</STATUS>
<group>
</Orders>
I am using the following xslt and it is working fine. Is there any way to improve this.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="OrderStatusUpdate/OrderStatusEvents">
<Orders>
<xsl:for-each-group select="OrderStatusEvent" group-by="OrderStatusDetails/OrderStatusDetail/StatusName">
<xsl:variable name="group-name" select="current-grouping-key()" />
<group name="{current-grouping-key()}">
<xsl:for-each-group select="current-group()" group-by="OrderId">
<xsl:variable name="order-id" select="current-grouping-key()" />
<xsl:element name="STATUS">
<xsl:attribute name="ID"><xsl:value-of select="$group-name" /></xsl:attribute>
<xsl:attribute name="DESCRIPTION">Goods <xsl:value-of select="$group-name" /></xsl:attribute>
<xsl:element name="ORDER">
<xsl:attribute name="ID"><xsl:value-of select="$order-id" /></xsl:attribute>
<xsl:for-each select="current-group()">
<xsl:if test="$group-name = 'Shipped'">
<xsl:call-template name="Shipped">
<xsl:with-param name="nodes">
<xsl:copy-of select="." />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:if test="$group-name = 'Cancelled'">
<xsl:call-template name="Cancelled">
<xsl:with-param name="nodes">
<xsl:copy-of select="." />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:for-each-group>
</group>
</xsl:for-each-group>
</Orders>
</xsl:template>
<xsl:template name="Shipped">
<xsl:param name="nodes">
</xsl:param>
<xsl:element name="ORDER_ITEM">
<xsl:attribute name="ID"><xsl:value-of select="$nodes/OrderStatusEvent/ItemId" /></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="Cancelled">
<xsl:param name="nodes"></xsl:param>
<xsl:element name="ORDER_ITEM">
<xsl:attribute name="ID"><xsl:value-of select="$nodes/OrderStatusEvent/ItemId" /></xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
It is easier to use literal result elements and attribute value templates as long as you don't need to compute element or attribute names at run-time and I don't think you need the two templates and call-template, it suffices to use
<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:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="OrderStatusUpdate/OrderStatusEvents">
<Orders>
<xsl:for-each-group select="OrderStatusEvent" group-by="OrderStatusDetails/OrderStatusDetail/StatusName">
<xsl:variable name="group-name" select="current-grouping-key()" />
<group name="{current-grouping-key()}">
<xsl:for-each-group select="current-group()" group-by="OrderId">
<xsl:variable name="order-id" select="current-grouping-key()" />
<STATUS ID="{$group-name}" DESCRIPTION="Goods {$group-name}">
<ORDER ID="{$order-id}">
<xsl:apply-templates select="current-group()"/>
</ORDER>
</STATUS>
</xsl:for-each-group>
</group>
</xsl:for-each-group>
</Orders>
</xsl:template>
<xsl:template match="OrderStatusEvent">
<ORDER_ITEM ID="{ItemId}"/>
</xsl:template>
</xsl:stylesheet>

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>

Splitfunction gives troubles

I'm facing the following problem or challenge.
I've a an element in my source XML which can have 450 characters.
With my xslt I want to transform this into chunks of 75 characters.
...
<T61>
<parentInfo>SomeInfo</parentInfo>
<T86>
<info>abcdefghijklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz01234567890</info>
</T86>
</T61>
...
The output I generate should look something like:
<T31>
<x>abcdefghijklmnopqrstuvwxyz01234567890</x>
</T31>
<T31>
<x>abcdefghijklmnopqrstuvwxyz01234567890</x>
</T31>
In my code I use an template for T61 which does his work.
I thought to create another template for T86 and call this from inside the T61 template but this seems not to work because I've the complete string. I created an function which could split up the string in parts of 75. But the outcome of the function is still the complete string.
I used a function from an earlier post:
<xsl:function name="my:splitItUp" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="chunk-size" as="xs:integer"/>
<xsl:value-of>
<xsl:for-each-group select="string-to-codepoints($input)" group-by="(position() -1) idiv $chunk-size">
<xsl:sequence select="codepoints-to-string(current-group())"/>
</xsl:for-each-group>
</xsl:value-of>
</xsl:function>
...
<xsl:template match="T86">
<xsl:for-each select="my:splitItUp(info, 75)">
<T31>
<communication>
<xsl:value-of select="." />
</communication>
</T31>
</xsl:for-each>
</xsl:template>
This structure always result in a complete string. In debug I see it split it up but it concatenates the result together. Can I somehow come out of the function?
Best Regards Dirk
Please have a look this XSLT where you need to set <xsl:param name="stringRequired" select="xs:integer(13)"/> to chunk text:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" encoding="utf-8"/>
<xsl:param name="XML">
<info>abcdefghijklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz01234567890</info>
</xsl:param>
<xsl:param name="stringRequired" select="xs:integer(13)"/>
<xsl:param name="XMLLenfgh" select="string-length($XML)"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$XMLLenfgh gt $stringRequired">
<xsl:call-template name="getPart"/>
</xsl:when>
<xsl:otherwise>
<T31>
<x>
<xsl:value-of select="$XML/info"/>
</x>
</T31>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="getPart">
<xsl:param name="XML" select="$XML"/>
<xsl:param name="stringRequired" select="$stringRequired"/>
<xsl:param name="XMLLenfgh" select="$XMLLenfgh"/>
<xsl:message>
<xsl:value-of select="$XML"/>
</xsl:message>
<xsl:if test="$XMLLenfgh gt $stringRequired">
<T>
<x>
<xsl:value-of select="substring($XML,1,$stringRequired)"/>
</x>
</T>
<xsl:call-template name="getPart">
<xsl:with-param name="XML"
select="substring($XML,string-length(substring($XML,1,$stringRequired)))"/>
<xsl:with-param name="XMLLenfgh"
select="string-length(substring($XML,string-length(substring($XML,1,$stringRequired))))"/>
<xsl:with-param name="stringRequired" select="$stringRequired"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
OUTPUT:
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>abcdefghijklm</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>mnopqrstuvwxy</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>yz01234567890</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>0abcdefghijkl</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>lmnopqrstuvwx</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>xyz0123456789</x>
</T>

XSLT Wrapping text with multiple tags

I have this span element with a class of autbib-pc-bold-italic
<span class="autbib-pc-bold-italic">autbib</span>
I want to create element tags base on the #class attribute value:
My output should be:
<autbib><pc><bold><italic>autbib</italic></bold></pc></autbib>
Here is my xsl templates:
<xsl:template match="span[contains(#class,'autbib')]">
<xsl:call-template name="pbib.loop">
<xsl:with-param name="count" select="count(tokenize(#class, '-'))"/>
<xsl:with-param name="class" select="tokenize(#class, '-')"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="pbib.loop">
<xsl:param name="index" select="1" />
<xsl:param name="count" select="count(tokenize(#class, '-')) + 1"/>
<xsl:param name="class" select="tokenize(#class, '-')"/>
<xsl:element name="{$class[1]}">
<xsl:if test="not($index = $count)">
<xsl:element name="{$class[$index]}">
<xsl:apply-templates/>
</xsl:element>
</xsl:if>
</xsl:element>
<xsl:if test="not($index = $count)">
<xsl:call-template name="pbib.loop">
<xsl:with-param name="index" select="$index + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
And have this output which is wrong:
<autbib>
<pc>autbib</pc>
<bold>autbib</bold>
<italic>autbib</italic>
</autbib>
I need to have this output:
<autbib>
<pc>
<bold>
<italic>autbib</italic>
</bold>
</pc>
</autbib>
My problem is that I'm not sure where I should place xsl:apply-template so that tags wrap with each other.
Here is my suggestion:
<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 indent="yes"/>
<xsl:template match="span[contains(#class,'autbib')]">
<xsl:param name="classes" select="tokenize(#class, '-')"/>
<xsl:choose>
<xsl:when test="not($classes[1])">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$classes[1]}">
<xsl:apply-templates select=".">
<xsl:with-param name="classes" select="$classes[position() gt 1]"/>
</xsl:apply-templates>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
With Saxon 9.4 that transforms the input
<span class="autbib-pc-bold-italic">autbib</span>
into the result
<autbib>
<pc>
<bold>
<italic>autbib</italic>
</bold>
</pc>
</autbib>

Resources