issue with xsl-key for multiple elements - xslkey

I am trying to display the Hoursofoperation for different departments,i have a template that is working for single HoursofOperation element for multiple HoursofOperation elements it is not giving expected result. code is below
<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:key name="similarDays"
match="DaysOfWeek"
use="concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure)" />
<xsl:template match="/">
<xsl:for-each select="dealers/HoursOfOperation">
<xsl:if test="HoursTypeCode ='Service'">
From service:
<xsl:for-each select="DaysOfWeek[count(. | key('similarDays', concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))[1]) = 1]">
<xsl:for-each select="key('similarDays', concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))">
<dt>
<xsl:value-of select="substring(DayOfWeekCode,1,3)"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</dt>
</xsl:for-each>
<dd>
<xsl:call-template name="minutes2time">
<xsl:with-param name="minutes" select="AvailabilityStartTimeMeasure"/>
</xsl:call-template>
<xsl:text> - </xsl:text>
<xsl:call-template name="minutes2time">
<xsl:with-param name="minutes" select="AvailabilityEndTimeMeasure"/>
</xsl:call-template>
</dd>
</xsl:for-each>
</xsl:if>
<xsl:if test="HoursTypeCode ='Sales'">
From Sales:
<xsl:for-each select="DaysOfWeek[count(. | key('similarDays', concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))[1]) = 1]">
<xsl:for-each select="key('similarDays', concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))">
<dt>
<xsl:value-of select="substring(DayOfWeekCode,1,3)"/>
<xsl:if test="position()!=last()">
<xsl:text>, </xsl:text>
</xsl:if>
</dt>
</xsl:for-each>
<dd>
<xsl:call-template name="minutes2time">
<xsl:with-param name="minutes" select="AvailabilityStartTimeMeasure"/>
</xsl:call-template>
<xsl:text>am - </xsl:text>
<xsl:call-template name="minutes2time">
<xsl:with-param name="minutes" select="AvailabilityEndTimeMeasure"/>
</xsl:call-template>
<xsl:text>pm</xsl:text>
</dd>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="minutes2time">
<xsl:param name="minutes"/>
<xsl:variable name="h" select="floor($minutes div 60)"/>
<xsl:variable name="m" select="$minutes mod 60"/>
<xsl:variable name="pad" select="substring('0', 1, $m < 10)"/>
<xsl:choose>
<xsl:when test="$h > 12">
<xsl:value-of select="concat(($h)-12, ':', $pad, $m)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($h, ':', $pad, $m)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XML:-
<dealers>
<HoursOfOperation>
<HoursTypeCode>Service</HoursTypeCode>
<DaysOfWeek>
<DayOfWeekCode>Monday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Tuesday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Wednesday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Thursday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Friday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Saturday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Sunday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
</HoursOfOperation>
<HoursOfOperation>
<HoursTypeCode>Parts</HoursTypeCode>
<DaysOfWeek>
<DayOfWeekCode>Monday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">480</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1050</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Tuesday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">480</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1050</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Wednesday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">480</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1050</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Thursday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">480</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1050</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Friday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">480</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1050</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Saturday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">480</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">990</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Sunday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">420</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
</HoursOfOperation>
<HoursOfOperation>
<HoursTypeCode>Sales</HoursTypeCode>
<DaysOfWeek>
<DayOfWeekCode>Monday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">510</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1140</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Tuesday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">510</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1140</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Wednesday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">510</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1140</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Thursday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">510</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1140</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Friday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">510</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1140</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Saturday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">600</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
<DaysOfWeek>
<DayOfWeekCode>Sunday</DayOfWeekCode>
<AvailabilityStartTimeMeasure unitCode="minute">660</AvailabilityStartTimeMeasure>
<AvailabilityEndTimeMeasure unitCode="minute">1080</AvailabilityEndTimeMeasure>
</DaysOfWeek>
</HoursOfOperation>
</dealers>
Output:-
From service:Mon, Tue, Wed, Thu, Fri, Sat, Sun, Sun7:00 - 6:00 From
Sales:Mon, Tue, Wed, Thu, Fri8:30am - 7:00pmSat10:00am -
6:00pmSun11:00am - 6:00pm
template is working fine for Sales HoursOfOperation element but for service it is not working as expected.i didn't understand what this select statement is doing exactly <xsl:for-each select="DaysOfWeek[count(. | key('similarDays', concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))[1]) = 1]">
Desired output:-
From service:Mon - Sun 7:00am - 6:00pm
From Sales:Mon - Fri 8:30am - 7:00pm
Sat 10:00am - 6:00pm
Sun 11:00am - 6:00pm

DaysOfWeek[count(. | key('similarDays', concat(AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))[1]) = 1]
is an instance of the "Muenchian grouping" method, a way to group elements together based on some value that they have in common. This particular expression will select all the DaysOfWeek children of the current context element which are the first mention of their particular combination of start and end times within the whole document.
If you want to use Muenchian grouping but limit it to group within a particular section of the document then you need to include something that uniquely identifies that section as part of the key value (so that the first element with start time 1 and end time 2 within section A has a different key value from the first element with the same start and end time but within section B). For your case, a suitable unique identifier might be the HoursTypeCode:
<xsl:key name="similarDays"
match="DaysOfWeek"
use="concat(../HoursTypeCode, '|',
AvailabilityStartTimeMeasure, '|',
AvailabilityEndTimeMeasure)" />
The grouping expression needs to include the same unique identifier
<xsl:if test="HoursTypeCode ='Service'">
From service:
<xsl:for-each select="DaysOfWeek[count(. |
key('similarDays', concat('Service|', AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))[1]) = 1]">
<xsl:for-each select="key('similarDays', concat('Service|', AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))">
Of course, rather than the <xsl:if> blocks duplicating the whole set of logic for "from sales" and "from service" you could handle them both in the same block taking the section name from HoursTypeCode:
<xsl:for-each select="dealers/HoursOfOperation">
From <xsl:value-of select="HoursTypeCode"/>:
<xsl:for-each select="DaysOfWeek[count(. |
key('similarDays', concat(current()/HoursTypeCode, '|', AvailabilityStartTimeMeasure, '|', AvailabilityEndTimeMeasure))[1]) = 1]">
<!-- etc. -->

Related

Subtraction by decimal number

I have a to subtract the amount -1 based on the condition.Please any one help.
Input:
<JD>
<GP xmlns="">
I xmlns="">
<PK>40</PK>
<A/>
<AMNT>11659650.15</AMNT>
<B/>
<C/>
</I>
<I xmlns="">
<PK>50</PK>
<A/>
<AMNT>11659650.15</AMNT>
<B/>
<C/>
</I>
</GP>
</JD>
Tried with below XSLT and got 1.165964915E7 for 50.
<xsl:for-each select="JD/mo:GP/I">
<xsl:if test="PK='40'">
<xsl:variable name="a" select="AMNT"/>
<xsl:element name="AMT">
<xsl:value-of select="$a"/>
</xsl:element>
</xsl:if>
<xsl:if test="PK='50'">
<xsl:variable name="a" select="AMNT"/>
<xsl:element name="AMT">
<xsl:value-of select="$a - 1"/>
</xsl:element>
</xsl:if>
Considering your given input as following:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<JD>
<GP>
<I>
<PK>40</PK>
<A />
<AMNT>11659650.15</AMNT>
<B />
<C />
</I>
<I>
<PK>50</PK>
<A />
<AMNT>11659650.15</AMNT>
<B />
<C />
</I>
</GP>
</JD>
</Root>
In XSLT 2.0, you can try it using xs:decimal as below:
<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="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/Root">
<xsl:for-each select="JD/mo:GP/I">
<xsl:if test="PK='40'">
<xsl:variable name="a" select="AMNT" />
<xsl:element name="AMT">
<xsl:value-of select="$a" />
</xsl:element>
</xsl:if>
<xsl:if test="PK='50'">
<xsl:variable name="a" select="AMNT" />
<xsl:element name="AMT">
<xsl:value-of select="xs:decimal($a) - 1" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>
In XSLT 1.0, Use the format-number() function:
<xsl:template match="/Root">
<xsl:for-each select="JD/mo:GP/I">
<xsl:if test="PK='40'">
<xsl:variable name="a" select="AMNT" />
<xsl:element name="AMT">
<xsl:value-of select="$a" />
</xsl:element>
</xsl:if>
<xsl:if test="PK='50'">
<xsl:variable name="a" select="AMNT" />
<xsl:element name="AMT">
<xsl:value-of select="format-number($a - 1, '0.##')" />
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:template>

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>

How to group the elements in XSL?

I have an HTML of the following process.
<p class="Reference_Unnum" id="RefId_2"><span class="first_name" dir="Author" value="Klingmann">Klingmann, </span><span class="last_name" dir="Author" value="Anna.">A</span>, <span class="first_name" dir="Author" value="John">John, </span><span class="last_name" dir="Author" value="Kumar">K</span>, <span class="first_name" dir="Author" value="William">William, </span><span class="last_name" dir="Author" value="Jaya">J</span> & <span class="first_name" dir="Author" value="Hannah">Hannah, </span><span class="last_name" dir="Author" value="Leslie.">L</span> <span class="chapter_title" value="Sample Chapter title">Sample Chapter title. </span>In: <span class="first_name" dir="Editor" value="Mihail">Mihail, </span><span class="last_name" dir="Editor" value="Popescu">P</span>, <span class="first_name" dir="Editor" value="Dong">Dong, </span><span class="last_name" dir="Editor" value="Xu">X</span> & <span class="first_name" dir="Editor" value="Hannah">Hannah, </span><span class="last_name" dir="Editor" value="Leslie.">L</span> (eds.) <span class="book_title" value="Sample Book title">Sample Book title.</span></p>
The author and editor name should be group. How it is possible to group first name and last name.
The output should be follow below.
<reference>
<authors>
<author>
<given-name>Klingmann</given-name>
<surname>A</surname>
</author>
<author>
<given-name>John</given-name>
<surname>K</surname>
</author>
<author>
<given-name>William</given-name>
<surname>J</surname>
</author>
<author>
<given-name>Hannah</given-name>
<surname>L</surname>
</author>
</authors>
<chapter-title>Sample Chapter title</chapter-title>
<editors>
<editor>
<given-name>Mihail</given-name>
<surname>P</surname>
</editor>
<editor>
<given-name>Dong</given-name>
<surname>X</surname>
</editor>
<editor>
<given-name>Hannah</given-name>
<surname>L</surname>
</editor>
</editors>
<book-title>Sample Book title</book-title>
</reference>
Thanks in advance.
Here is a sample stylesheet:
<?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:template match="p[#class = 'Reference_Unnum']">
<reference>
<xsl:for-each-group select="span" group-by="(#dir, #class)[1]">
<xsl:choose>
<xsl:when test="current-group()[2]">
<xsl:element name="{lower-case(#dir)}s">
<xsl:for-each-group select="current-group()" group-starting-with="span[#class = 'first_name']">
<xsl:element name="{lower-case(#dir)}">
<xsl:apply-templates select="current-group()"/>
</xsl:element>
</xsl:for-each-group>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</reference>
</xsl:template>
<xsl:template match="span[#class = 'first_name']">
<given-name>
<xsl:value-of select="#value"/>
</given-name>
</xsl:template>
<xsl:template match="span[#class = 'last_name']">
<surname>
<xsl:value-of select="."/>
</surname>
</xsl:template>
<xsl:template match="span[#class = 'chapter_title']">
<chapter-title>
<xsl:value-of select="#value"/>
</chapter-title>
</xsl:template>
<xsl:template match="span[#class = 'book_title']">
<book-title>
<xsl:value-of select="#value"/>
</book-title>
</xsl:template>
</xsl:stylesheet>

Limiting output (XSLT 2.0 Temporary Tree)

A co-worker and I have been given a new requirement. Please review the following.
We have a requirement to transform an XML source document while enforcing a numerical limit on certain items in the result document. A source document, an XSLT stylesheet, and a result document are reproduced below. This result document, however, does not reflect the desired numerical limit, because this stylesheet transforms the source document without any restriction.
At the end, our question will be: How can the desired numerical limit be enforced in the stylesheet?
Source document:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<T:Message xmlns="http://www.noname.com/Platform" xmlns:T="http://www.noname.com/Transportation">
<T:ShipmentListMessage>
<Shipment>
<ShipmentNumber>ABC</ShipmentNumber>
<PickupCommodityCode>Hazmat</PickupCommodityCode>
<DeliveryCommodityCode>Hazmat</DeliveryCommodityCode>
<ShipmentLine>
<ShipmentLineNumber>ABC-1</ShipmentLineNumber>
<OrderLineItemNumber>1</OrderLineItemNumber>
</ShipmentLine>
<ShipmentLine>
<ShipmentLineNumber>ABC-2</ShipmentLineNumber>
<OrderLineItemNumber>2</OrderLineItemNumber>
</ShipmentLine>
<ShipmentLine>
<ShipmentLineNumber>ABC-3</ShipmentLineNumber>
<OrderLineItemNumber>3</OrderLineItemNumber>
</ShipmentLine>
</Shipment>
<Shipment>
<ShipmentNumber>DEF</ShipmentNumber>
<PickupCommodityCode>Hazmat</PickupCommodityCode>
<DeliveryCommodityCode>Hazmat</DeliveryCommodityCode>
<ShipmentLine>
<ShipmentLineNumber>DEF-1</ShipmentLineNumber>
<OrderLineItemNumber>1</OrderLineItemNumber>
</ShipmentLine>
<ShipmentLine>
<ShipmentLineNumber>DEF-2</ShipmentLineNumber>
<OrderLineItemNumber>2</OrderLineItemNumber>
</ShipmentLine>
</Shipment>
<Shipment>
<ShipmentNumber>GHI</ShipmentNumber>
<PickupCommodityCode>Hazmat</PickupCommodityCode>
<DeliveryCommodityCode>Hazmat</DeliveryCommodityCode>
<ShipmentLine>
<ShipmentLineNumber>GHI-1</ShipmentLineNumber>
<OrderLineItemNumber>1</OrderLineItemNumber>
</ShipmentLine>
<ShipmentLine>
<ShipmentLineNumber>GHI-2</ShipmentLineNumber>
<OrderLineItemNumber>2</OrderLineItemNumber>
</ShipmentLine>
<ShipmentLine>
<ShipmentLineNumber>GHI-3</ShipmentLineNumber>
<OrderLineItemNumber>3</OrderLineItemNumber>
</ShipmentLine>
<ShipmentLine>
<ShipmentLineNumber>GHI-4</ShipmentLineNumber>
<OrderLineItemNumber>4</OrderLineItemNumber>
</ShipmentLine>
</Shipment>
</T:ShipmentListMessage>
<T:MovementListMessage>
<Movement>
<MovementStop>
<StopSequenceNumber>0</StopSequenceNumber>
<MovementStopLine>
<OperationType>Pickup</OperationType>
<ShipmentNumber>ABC</ShipmentNumber>
</MovementStopLine>
<MovementStopLine>
<OperationType>Pickup</OperationType>
<ShipmentNumber>DEF</ShipmentNumber>
</MovementStopLine>
<MovementStopLine>
<OperationType>Pickup</OperationType>
<ShipmentNumber>GHI</ShipmentNumber>
</MovementStopLine>
</MovementStop>
<MovementStop>
<StopSequenceNumber>1</StopSequenceNumber>
<MovementStopLine>
<OperationType>Deliver</OperationType>
<ShipmentNumber>ABC</ShipmentNumber>
</MovementStopLine>
</MovementStop>
<MovementStop>
<StopSequenceNumber>2</StopSequenceNumber>
<MovementStopLine>
<OperationType>Deliver</OperationType>
<ShipmentNumber>DEF</ShipmentNumber>
</MovementStopLine>
<MovementStopLine>
<OperationType>Deliver</OperationType>
<ShipmentNumber>GHI</ShipmentNumber>
</MovementStopLine>
</MovementStop>
</Movement>
</T:MovementListMessage>
</T:Message>
XSLT Stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.noname.com/Transportation" xmlns:vc="http://www.noname.com/Platform">
<xsl:output method="text" indent="no"/>
<xsl:template match="t:Message">
<xsl:variable name="shipmentPath" select="t:ShipmentListMessage/vc:Shipment"/>
<xsl:variable name="movementPath" select="t:MovementListMessage/vc:Movement"/>
<xsl:variable name="numDeliverLocations" select="count($movementPath/vc:MovementStop/vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
<xsl:variable name="numOffers" select="count($shipmentPath)"/>
<xsl:for-each select="$movementPath/vc:MovementStop">
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
<xsl:if test="position() = 1">
S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*UL<xsl:text>~</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
<xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
<xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:DeliveryCommodityCode != '']">
<xsl:choose>
<xsl:when test="vc:DeliveryCommodityCode = 'Hazmat'">
<xsl:if test="$numOffers gt 1 or $numDeliverLocations = 1">
<xsl:for-each select="vc:ShipmentLine">
<xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
<xsl:choose>
<xsl:when test="$OfferCount eq 1">
L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text>
</xsl:when>
<xsl:when test="position() lt 10">
L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
</xsl:when>
<xsl:otherwise>
L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
<xsl:if test="position() = 1">
S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*LD<xsl:text>~</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
<xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
<xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:PickupCommodityCode != '']">
<xsl:choose>
<xsl:when test="vc:PickupCommodityCode = 'Hazmat'">
<xsl:for-each select="vc:ShipmentLine">
<xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
<xsl:choose>
<xsl:when test="$OfferCount eq 1">
L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text>
</xsl:when>
<xsl:when test="position() lt 10">
L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
</xsl:when>
<xsl:otherwise>
L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Result document:
S5*1*LD~
L5*101~
L5*102~
L5*103~
L5*201~
L5*202~
L5*301~
L5*302~
L5*303~
L5*304~
S5*2*UL~
L5*1~
L5*2~
L5*3~
S5*3*UL~
L5*101~
L5*102~
L5*201~
L5*202~
L5*203~
L5*204~
In order to satisfy our requirement, the numerical limit must somehow be built into the stylesheet. For the purpose of this discussion, the desired limit is 5 on the number of “L5” segments following an “S5” segment. In this example, the limit will reduce the number of “L5” segments to 5 each following “S5*1*LD” and “S5*3*UL”. The limit will not come into play in the case of “S5*2*UL”.
Desired result document with the “L5” limit applied:
S5*1*LD~
L5*101~
L5*102~
L5*103~
L5*201~
L5*202~
S5*2*UL~
L5*1~
L5*2~
L5*3~
S5*3*UL~
L5*101~
L5*102~
L5*201~
L5*202~
L5*203~
Again, our question is: How can the desired numerical limit be coded in the stylesheet?
I think you could store the first result in a variable and then group and count as needed, for easier processing I have chosen to wrap the intermediary result as XML:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:t="http://www.noname.com/Transportation" xmlns:vc="http://www.noname.com/Platform"
exclude-result-prefixes="t vc">
<xsl:output method="text"/>
<xsl:template match="t:Message">
<xsl:variable name="shipmentPath" select="t:ShipmentListMessage/vc:Shipment"/>
<xsl:variable name="movementPath" select="t:MovementListMessage/vc:Movement"/>
<xsl:variable name="numDeliverLocations" select="count($movementPath/vc:MovementStop/vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
<xsl:variable name="numOffers" select="count($shipmentPath)"/>
<xsl:variable name="items">
<xsl:for-each select="$movementPath/vc:MovementStop">
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
<xsl:if test="position() = 1">
<item>S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*UL<xsl:text>~</xsl:text></item>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Deliver']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Deliver'])"/>
<xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
<xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:DeliveryCommodityCode != '']">
<xsl:choose>
<xsl:when test="vc:DeliveryCommodityCode = 'Hazmat'">
<xsl:if test="$numOffers gt 1 or $numDeliverLocations = 1">
<xsl:for-each select="vc:ShipmentLine">
<xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
<xsl:choose>
<xsl:when test="$OfferCount eq 1">
<item>L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text></item>
</xsl:when>
<xsl:when test="position() lt 10">
<item>L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
</xsl:when>
<xsl:otherwise>
<item>L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
<xsl:if test="position() = 1">
<item>S5*<xsl:value-of select="../vc:StopSequenceNumber+1"/>*LD<xsl:text>~</xsl:text></item>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="vc:MovementStopLine[vc:OperationType = 'Pickup']">
<xsl:variable name="OfferNumber" select="vc:ShipmentNumber"/>
<xsl:variable name="OfferCount" select="count(../vc:MovementStopLine[vc:OperationType = 'Pickup'])"/>
<xsl:variable name="OfferPosition" select="if (position() lt 10) then position() else 0"/>
<xsl:for-each select="$shipmentPath[vc:ShipmentNumber = $OfferNumber and vc:PickupCommodityCode != '']">
<xsl:choose>
<xsl:when test="vc:PickupCommodityCode = 'Hazmat'">
<xsl:for-each select="vc:ShipmentLine">
<xsl:variable name="ShipmentLine" select="vc:ShipmentLineNumber"/>
<xsl:choose>
<xsl:when test="$OfferCount eq 1">
<item>L5*<xsl:value-of select="vc:OrderLineItemNumber"/><xsl:text>~</xsl:text></item>
</xsl:when>
<xsl:when test="position() lt 10">
<item>L5*<xsl:value-of select="concat($OfferPosition, '0', vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
</xsl:when>
<xsl:otherwise>
<item>L5*<xsl:value-of select="concat($OfferPosition, vc:OrderLineItemNumber)"/><xsl:text>~</xsl:text></item>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:for-each-group select="$items/item" group-starting-with="item[starts-with(., 'S5*')]">
<xsl:if test="position() gt 1"><xsl:text>
</xsl:text></xsl:if>
<xsl:value-of select="if (starts-with(., 'S5*1*LD') or starts-with(., 'S5*3*UL'))
then current-group()[position() le 6] else current-group()"
separator="
"/>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
With that stylesheet and your input Saxon 9.5 outputs
S5*1*LD~
L5*101~
L5*102~
L5*103~
L5*201~
L5*202~
S5*2*UL~
L5*1~
L5*2~
L5*3~
S5*3*UL~
L5*101~
L5*102~
L5*201~
L5*202~
L5*203~

extracting sql data from xml

Let me know your suggestions to extract SQL data from xml. The sample xml would be as below given as input to a procedure as a CLOB:
<filter>
<and>
<or>
<equals field="MARKET_NAME" value="Chicago"/>
<equals field="MARKET_NAME" value="BOSTON"/>
</or>
<or>
<equals field="RANK" value="1"/>
<equals field="RANK" value="2"/>
</or>
<between field="current_data" arg1="start_date" arg2="End_date"/>
<gt field="CUME" value="20"/>
<like field="DMA_NAME" value="%ABC%"/>
</and>
</filter>
The extracted data should look something like this :
(MARKET_NAME = 'Chicago' or MARKET_NAME = 'BOSTON') and
(RANK = 1 or RANK = 2) and
(current_date between start_date and End_Date) and
CUME > 20 and
DMA_NAME like '%ABC%'
Let me know your valuable tips..
Thanks in advance
one approach would be a XSL stylesheet.
but I would add to your XML, datatype. e.g.
<filter>
<and>
<or>
<equals field="MARKET_NAME" value="Chicago" datatype="string"/>
<equals field="MARKET_NAME" value="BOSTON" datatype="string"/>
</or>
<or>
<equals field="RANK" value="1" datatype="number"/>
<equals field="RANK" value="2" datatype="number"/>
</or>
<between field="current_data" arg1="start_date" arg2="End_date" datatype="field"/>
<between field="foo" arg1="20121230" arg2="20130101 01:12:23" datatype="date"/>
<gt field="CUME" value="20" datatype="number"/>
<like field="DMA_NAME" value="%ABC%" datatype="string"/>
</and>
</filter>
then an XSL (this is just a sample. you WILL need to improve this as its just a basic starter for you!)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="xd"
version="1.0">
<xsl:output method="text"/>
<xsl:template name="string-replace-all">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="by"/>
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$by"/>
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="by" select="$by"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="processDatatype">
<xsl:param name="value" />
<xsl:param name="datatype" />
<xsl:choose>
<xsl:when test="$datatype = 'string'">
<xsl:text>&apos;</xsl:text>
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="$value"/>
<xsl:with-param name="replace" select='"&apos;"'/>
<xsl:with-param name="by" select='"&apos;&apos;"'/>
</xsl:call-template>
<xsl:text>&apos;</xsl:text>
</xsl:when>
<xsl:when test="$datatype = 'date'">
<xsl:text>to_date(&apos;</xsl:text>
<xsl:value-of select="$value"/>
<xsl:text>&apos;,&apos;yyyymmdd hh24:mi:ss&apos;)</xsl:text>
</xsl:when>
<xsl:otherwise><xsl:value-of select="$value"/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="gt">
<xsl:value-of select="#field"/>
<xsl:text> > </xsl:text>
<xsl:call-template name="processDatatype">
<xsl:with-param name="value"><xsl:value-of select="#value"/></xsl:with-param>
<xsl:with-param name="datatype"><xsl:value-of select="#datatype"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="lt">
<xsl:value-of select="#field"/>
<xsl:text> < </xsl:text>
<xsl:call-template name="processDatatype">
<xsl:with-param name="value"><xsl:value-of select="#value"/></xsl:with-param>
<xsl:with-param name="datatype"><xsl:value-of select="#datatype"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="between">
<xsl:value-of select="#field"/>
<xsl:text> between </xsl:text>
<xsl:call-template name="processDatatype">
<xsl:with-param name="value"><xsl:value-of select="#arg1"/></xsl:with-param>
<xsl:with-param name="datatype"><xsl:value-of select="#datatype"/></xsl:with-param>
</xsl:call-template>
<xsl:text> and </xsl:text>
<xsl:call-template name="processDatatype">
<xsl:with-param name="value"><xsl:value-of select="#arg2"/></xsl:with-param>
<xsl:with-param name="datatype"><xsl:value-of select="#datatype"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="like">
<xsl:value-of select="#field"/>
<xsl:text> like </xsl:text>
<xsl:call-template name="processDatatype">
<xsl:with-param name="value"><xsl:value-of select="#value"/></xsl:with-param>
<xsl:with-param name="datatype"><xsl:value-of select="#datatype"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="equals">
<xsl:value-of select="#field"/>
<xsl:text> = </xsl:text>
<xsl:call-template name="processDatatype">
<xsl:with-param name="value"><xsl:value-of select="#value"/></xsl:with-param>
<xsl:with-param name="datatype"><xsl:value-of select="#datatype"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
<xsl:template name="and">
<xsl:for-each select="*">
<xsl:if test="position() != 1">
<xsl:text>and </xsl:text>
</xsl:if>
<xsl:choose>
<xsl:when test="name() = 'like'">
<xsl:text>(</xsl:text>
<xsl:call-template name="like" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'gt'">
<xsl:text>(</xsl:text>
<xsl:call-template name="gt" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'lt'">
<xsl:text>(</xsl:text>
<xsl:call-template name="lt" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'equals'">
<xsl:text>(</xsl:text>
<xsl:call-template name="equals" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'between'">
<xsl:text>(</xsl:text>
<xsl:call-template name="between" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'or'">
<xsl:text>(</xsl:text>
<xsl:call-template name="or" />
<xsl:text>)
</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template name="or">
<xsl:for-each select="*">
<xsl:if test="position() != 1">
<xsl:text>or </xsl:text>
</xsl:if>
<xsl:choose>
<xsl:when test="name() = 'like'">
<xsl:text>(</xsl:text>
<xsl:call-template name="like" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'gt'">
<xsl:text>(</xsl:text>
<xsl:call-template name="gt" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'lt'">
<xsl:text>(</xsl:text>
<xsl:call-template name="lt" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'equals'">
<xsl:text>(</xsl:text>
<xsl:call-template name="equals" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'between'">
<xsl:text>(</xsl:text>
<xsl:call-template name="between" />
<xsl:text>)
</xsl:text>
</xsl:when>
<xsl:when test="name() = 'and'">
<xsl:text>(</xsl:text>
<xsl:call-template name="and" />
<xsl:text>)
</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
<xsl:template match="/filter">
<xsl:text>where </xsl:text>
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="name() = 'and'">
<xsl:call-template name="and" />
</xsl:when>
<xsl:when test="name() = 'or'">
<xsl:call-template name="or" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
example:
out XSL stored as an XMLTYPE:
SQL> select * from xsl;
NAME
--------------------
XSL
--------------------------------------------------------------------------------
xml_to_sql
<?xml version="1.0" encoding="WINDOWS-1252"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xd="http:
//www.oxygenxml.com/ns/doc/xsl" exclude-result-prefixes="xd" version="1.0">
<xsl:output method="text"/>
<xsl:template name="string-replace-all">
<xsl:param name="text"/>
...
now we use the transform function of XMLTYPE on the input XML to get the result:
SQL> select dbms_xmlgen.convert(xmltype('<?xml-stylesheet type="text/xsl" href="test.xsl"?>
2 <filter>
3 <and>
4 <or>
5 <equals field="MARKET_NAME" value="Chicago" datatype="string"/>
6 <equals field="MARKET_NAME" value="BOSTON" datatype="string"/>
7 </or>
8 <or>
9 <equals field="RANK" value="1" datatype="number"/>
10 <equals field="RANK" value="2" datatype="number"/>
11 </or>
12 <between field="current_data" arg1="start_date" arg2="End_date" datatype="field"/>
13 <between field="foo" arg1="20121230" arg2="20130101 01:12:23" datatype="date"/>
14 <gt field="CUME" value="20" datatype="number"/>
15 <like field="DMA_NAME" value="%AB&apos;C%" datatype="string"/>
16 </and>
17 </filter>').transform(xsl.xsl).getclobval(), 1)
18 from xsl
19 /
DBMS_XMLGEN.CONVERT(XMLTYPE('<
--------------------------------------------------------------------------------
where ((MARKET_NAME = 'Chicago')
or (MARKET_NAME = 'BOSTON')
)
and ((RANK = 1)
or (RANK = 2)
)
and (current_data between start_date and End_date)
and (foo between to_date('20121230','yyyymmdd hh24:mi:ss') and to_date('20130101
01:12:23','yyyymmdd hh24:mi:ss'))
and (CUME > 20)
and (DMA_NAME like '%AB''C%')

Resources