How can I handle error Exception with try/catch using xslt 3.0 - xslt-3.0

How can I handle error Exception with try/catch using xslt 3.0. I am finding in xml number Element. If number Element not find in parent product then generate a file error.txt and how to write the Exception.
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<catalog>
<product dept="WMN">
<name language="en">Fleece Pullover</name>
<colorChoices>navy black</colorChoices>
</product>
<product dept="ACC">
<number>563</number>
<name language="en">Floppy Sun Hat</name>
</product>
<product dept="ACC">
<number>443</number>
<name language="en">Deluxe Travel Bag</name>
</product>
<product dept="MEN">
<number>784</number>
<name language="en">Cotton Dress Shirt</name>
<colorChoices>white gray</colorChoices>
<desc>Our <i>favorite</i> shirt!</desc>
</product>
</catalog>
Using XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:err="http://www.w3.org/2005/xqt-errors"
exclude-result-prefixes="xs"
version="3.0">
<xsl:template match="/">
<xsl:stream href="books.xml">
<xsl:iterate select="catalog">
<xsl:result-document href="out.xml" omit-xml-declaration="no" indent="yes">
<xsl:copy>
<xsl:for-each select="product">
<xsl:try>
<xsl:copy-of select="number"/>
<xsl:catch>
<xsl:result-document href="error.txt">
<xsl:message>Element number not given in <xsl:value-of select="product/#dept"/></xsl:message>
<error code="{$err:code}" message="{$err:description}"/>
</xsl:result-document>
</xsl:catch>
</xsl:try>
</xsl:for-each>
</xsl:copy>
</xsl:result-document>
</xsl:iterate>
</xsl:stream>
</xsl:template>
</xsl:stylesheet>
My requirement is how can I uses try/catch when not find the number element then make a file with error.

Try this to generate error message in log file by taking the value in variable in then check some conditon:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:err="http://www.w3.org/2005/xqt-errors"
exclude-result-prefixes="xs"
version="3.0">
<xsl:template match="/">
<xsl:stream href="books.xml">
<xsl:iterate select="catalog">
<xsl:result-document href="out.xml" omit-xml-declaration="no" indent="yes">
<xsl:copy>
<xsl:for-each select="product">
<xsl:variable name="num" select="if (number) then (number) else ('aaaa')"/>
<xsl:try>
<number>
<xsl:value-of select="format-number($num, '############')"/>
</number>
<xsl:catch>
<xsl:result-document href="error.log" omit-xml-declaration="yes">
<xsl:value-of select="concat(' Element number not given in ', #dept)"/>
<xsl:value-of select="concat(' Error code: ', $err:code, ' and Error Desc is: ', $err:description)"/>
</xsl:result-document>
</xsl:catch>
</xsl:try>
</xsl:for-each>
</xsl:copy>
</xsl:result-document>
</xsl:iterate>
</xsl:stream>
</xsl:template>
</xsl:stylesheet>

Related

extract and print values only when they exist using xslt

The source xml is:
<?xml version="1.0" encoding="UTF-8" ?>
<mr:collection
xmlns:mr="http://www.lc.gov/mr2/slim"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.lc.gov/mr2/slim http://www.lc.gov/standards/mrxml/schema/mr21slim.xsd">
<mr:rc>
<mr:ctr tg="1000">311</mr:ctr>
<mr:dtf tg="12000" i1="1" i2=" ">
<mr:sbf cd="d">John Diter</mr:sbf>
</mr:dtf>
</mr:rc>
</mr:collection>
the xsl that i use:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://www.example.com"
xpath-default-namespace="http://www.lc.gov/mr2/slim"
xmlns:mr="http://www.lc.gov/mr2/slim"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="collection">
<O-PM>
<ListRcs>
<xsl:apply-templates/>
</ListRcs>
</O-PM>
</xsl:template>
<xsl:template match="rc">
<rc>
<xsl:apply-templates/>
</rc>
</xsl:template>
<xsl:template match="mr:ctr[#tg = 1000]">
<xsl:variable name="dz" as="xs:string">{tg ='1000'}!</xsl:variable><d:z xml:lang="en">{normalize-space($dz)}</d:z>
</xsl:template>
<xsl:template match="mr:dtf[#tg = 12000]">
<xsl:variable name="ds" as="xs:string">{sbf[#cd = 'a']}!</xsl:variable><d:s xml:lang="en">{normalize-space($ds)}</d:s>
<xsl:variable name="dp" as="xs:string">{sbf[#cd = 'c']}!</xsl:variable><d:p>{normalize-space($dp)}</d:p>
<xsl:variable name="dc" as="xs:string">{sbf[#cd = 'd']}!</xsl:variable><d:c>{normalize-space($dc)}</d:c>
</xsl:template>
</xsl:stylesheet>
Current output:
<?xml version="1.0" encoding="UTF-8"?>
<O-PM>
<ListRcs>
<rc>
<d:z xmlns:d="http://www.example.com">false!</d:z>
<d:s xmlns:d="http://www.example.com" xml:lang="en">!</d:s>
<d:p xmlns:d="http://www.example.com">!</d:p>
<d:c xmlns:d="http://www.example.com">John Diter!</d:c>
</rc>
</ListRcs>
</O-PM>
Desired output:
<?xml version="1.0" encoding="UTF-8"?>
<O-PM>
<ListRcs>
<rc>
<d:z xmlns:d="http://www.example.com">311</d:z>
<d:c xmlns:d="http://www.example.com">John Diter!</d:c>
</rc>
</ListRcs>
</O-PM>
For starters i need to get as output the value of tg = 1000 and not false,
and secondly, how can one print only the values that exist?
In the above example only the value that matches the criterion cd = d is TRUE.
https://xsltfiddle.liberty-development.net/asoTKA/2
It seems, this time you can just match on the elements that interest you:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://www.example.com"
xpath-default-namespace="http://www.lc.gov/mr2/slim"
xmlns:mr="http://www.lc.gov/mr2/slim"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-skip"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="collection">
<O-PM>
<ListRcs>
<xsl:apply-templates/>
</ListRcs>
</O-PM>
</xsl:template>
<xsl:template match="rc">
<rc>
<xsl:apply-templates/>
</rc>
</xsl:template>
<xsl:template match="mr:ctr[#tg = 1000]">
<d:z xml:lang="en">{.}</d:z>
</xsl:template>
<xsl:template match="dtf[#tg = 12000]/sbf[#cd = 'd']">
<d:c>{.}!</d:c>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/asoTKA/3
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:d="http://www.example.com"
xpath-default-namespace="http://www.lc.gov/mr2/slim"
xmlns:mr="http://www.lc.gov/mr2/slim"
exclude-result-prefixes="#all"
expand-text="yes"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="collection">
<O-PM>
<ListRcs>
<xsl:apply-templates/>
</ListRcs>
</O-PM>
</xsl:template>
<xsl:template match="rc">
<rc>
<xsl:apply-templates/>
</rc>
</xsl:template>
<xsl:template match="mr:ctr[#tg = 1000]">
<xsl:variable name="dz" as="xs:string"><xsl:value-of select="."/></xsl:variable>
<d:z xml:lang="en"><xsl:value-of select="normalize-space($dz)"/></d:z>
</xsl:template>
<xsl:template match="mr:dtf[#tg = 12000]">
<xsl:variable name="dc" as="xs:string">
<xsl:if test="mr:sbf[#cd = 'd']"><xsl:value-of select="normalize-space(.)"/> </xsl:if>
</xsl:variable>
<d:c xml:lang="en"><xsl:value-of select="normalize-space($dc)"/></d:c>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/asoTKA/5

Print xml nodes for each element in a single row

I need to print the category and hours values from all nodes in this xml as comma separated values in a single row through xslt -
XML
<?xml version="1.0" encoding="UTF-8"?>
<course>
<subcourse>
<code>ABC</code>
<name>REFCOURSE</name>
<date>Date</date>
<category>SDF</category>
<hours>7</hours>
</subcourse>
<subcourse>
<code>DEF</code>
<name>ORIGCOURSE</name>
<date>Date</date>
<category>UIT</category>
<hours>9</hours>
</subcourse>
</course>
Output needed -
SDF,7,UIT,9
By taking help from stakoverflow, here's what I've done so far -
<?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" version="2.0">
<xsl:param name="range-1-begin" select="4"/>
<xsl:param name="range-1-end" select="5"/>
<xsl:param name="range-2-begin" select="6"/>
<xsl:param name="range-2-end" select="7"/>
<xsl:output method="text" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="subcourse">
<info><xsl:apply-templates/></info>
</xsl:template>
<xsl:template match="subcourse">
<xsl:if test = "not(position()= 1)">
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Output - ABCREFCOURSEDateSDF7,DEFORIGCOURSEDateUIT9
I need it to iterate through every subcourse and pick category and hours if exist. I could not find how to pick only category and hours.
<?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" version="2.0">
<xsl:template match="//subcource">
<xsl:if test="category">
<xsl:if test = "not(position()=1)">
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:value-of select="category"/><xsl:text>,</xsl:text><xsl:value-of select="hours"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

Matching strings inside <![CDATA]>

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

Replacing one namespace with another

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

SharePoint Designer Data View- XSLT Count

I am working with a data view web part in SPD 2010. My xml structure is as follows:
<ProjectGroups>
<ProjectGroup>
<GroupID>1</GroupID>
<ProjectName>Project 1</ProjectName>
</ProjectGroup>
<ProjectGroup>
<GroupID>2</GroupID>
<ProjectName>Project 2</ProjectName>
</ProjectGroup>
<ProjectGroup>
<GroupID>2</GroupID>
<ProjectName>Project 3</ProjectName>
</ProjectGroup>
</ProjectGroups>
This is a rollup web part, so what I am looking to do is get a count of Projects under each Project group. For my example above, Group ID 1 has 1 project, Group ID 2 has 2. I am sure there's a way to do this, but I'm sort of learning xslt on the fly, so I'm not sure exactly what to do. Any help is appreciated. Thanks.
This style-sheet ...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="groups" match="ProjectGroup" use="GroupID" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="ProjectGroup[generate-id()=generate-id(key('groups',GroupID)[1])]">
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:attribute name="count-of-projects">
<xsl:value-of select="count(key('groups',GroupID))" />
</xsl:attribute>
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
... when applied to your input, will produce ...
<?xml version="1.0" encoding="utf-8"?>
<ProjectGroups>
<ProjectGroup count-of-projects="1">
<GroupID>1</GroupID>
<ProjectName>Project 1</ProjectName>
</ProjectGroup>
<ProjectGroup count-of-projects="2">
<GroupID>2</GroupID>
<ProjectName>Project 2</ProjectName>
</ProjectGroup>
<ProjectGroup>
<GroupID>2</GroupID>
<ProjectName>Project 3</ProjectName>
</ProjectGroup>
</ProjectGroups>

Resources