Apache Derby parsing XSLT - XALAN Error - derby

I'm making such a derby request:
SELECT XMLSERIALIZE(
XMLQUERY('
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="singleOrder">
<out><xsl:value-of select="."/></out>
</xsl:template>
</xsl:stylesheet>
' PASSING BY REF xml_col EMPTY ON
EMPTY) AS VARCHAR(10)
)AS ProductId
FROM xml_orders
But I'm getting such an exception:
java.sql.SQLException: Encountered error while evaluating XML query expression for xmlquery operator: com.sun.org.apache.xpath.internal.domapi.XPathStylesheetDOM3Exception: Prefix must resolve to a namespace: xsl
Why did I get it?
I've heard derby uses xalan which supports XSLT.

Related

Nokogiri XSLT can transform with invalid stylesheet

If I try to transform sample xml (target.xml)
<?xml version="1.0"?>
<root />
with invalid XSL stylesheet (invalid.xsl):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml" version="1.0">
<xsl:template match="/root">
<new-root />
</xsl:stylesheet>
</xsl:template>
using Nokogiri (1.6.8.1) ruby v2.1.9:
require 'nokogiri'
print Nokogiri::XSLT(File.open('invalid.xsl'))
.transform(Nokogiri::XML(File.open('target.xml')))
it will finish successfully:
# ruby program.rb
<?xml version="1.0"?>
<new-root xmlns="http://www.w3.org/1999/xhtml"/>
How to configure nokogiri to validate XSL and throw an error if it's invalid?

Deepest match first with XPath

I have a configuration file in xml, with increasing specificity. That is, the closest setting to some section is the setting that will be in effect, even if it is set on higher levels. A colleague suggested using XPath for this. But I'm not sure how it would work? I suppose I want to find the "deepest match" for the setting, then automatically backing out if there is no match.
For instance:
<Settings>
<Foo>Bar</Foo>
<Products>
<Bar>Baz</Bar>
<Product Name="Thingamabob">
<Foo>Baz</Foo>
</Product>
<Product Name="Whizbang">
<Bar>Foo</Bar>
</Product>
</Products>
</Settings>
Searching for the Bar setting for Thingamabob should return "Baz", but "Foo" on Whizbang. In the same way, Foo has a value of "Baz" for Thingamabob, but "Bar" on Whizbang.
Can this type of lookup be implemented with XPath?
Searching Foo on Thingamabob can be done like so
//*[#Name='Thingamabob']/ancestor-or-self::*/Foo
But this will give you two nodes, you want to obtain the node with the maximum count(ancestor::*) and then get its text() value
I don't know of a way to do max on a xml hierarchy like yours, use an external script to iterate over the node list given by the xpath to find the max depth, then grab its content.
EDIT:
You may be able to do this in XSLT 2.0, note I have not tested this.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:function name="my:lookup">
<xsl:param name="name"/>
<xsl:param name="arg"/>
<xsl:for-each select="//*[#Name='$name']/ancestor-or-self::*/$arg">
<xsl:sort select="count(ancestor::*)" data-type="number" order="descending"/>
<xsl:if test="position()=1"><xsl:value-of select="."/></xsl:if>
</xsl:for-each>
</xsl:function>
<xsl:template match="/">
<xsl:copy-of select="my:lookup('Thingamabob','Foo')" />
</xsl:template>
</xsl:stylesheet>
EDIT 2:
I've also figure this should work in XPATH 2.0 but I've not tested it
//*[#Name='Thingamabob']/ancestor-or-self::*/Foo[count(ancestor::*) >= //*[#Name='Thingamabob']/ancestor-or-self::*/Foo/count(ancestor::*)]/text()
If you know for certain that <Bar> will precede <Product>, you could do it with this:
//Product[#Name='Thingamabob']/preceding-sibling::Bar|//Product[#Name='Thingamabob']/Bar

Error XalanXPathException when using hours-from-duration xpath function in ibm db2 xslt transformation

Input XML:<test><TotalDuration>PT1H32M7S</TotalDuration></test>
Input XSLT:
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:template match="/test">
Hours=<xsl:value-of select="fn:hours-from-duration(TotalDuration)"/> hr
</xsl:template>
</xsl:stylesheet>
Expected Output: Hours=1 hr
Instead Getting: [IBM][DB2/NT64] SQL16280N The XSLT processor returned the following error: "XalanXPathException: The function number 'http://www.w3.org/2005/xpath". SQLSTATE=225X0
Expected Output: Hours=1 hr
Instead Getting: [IBM][DB2/NT64]
SQL16280N The XSLT processor returned
the following error:
"XalanXPathException: The function
number 'http://www.w3.org/2005/xpath".
SQLSTATE=225X0
This is so clear: The XSLT processor you are using (Xalan) doesn't implement XSLT 2.0.
You need to feed XSLT 2.0 code only to a XSLT processor that implements XSLT 2.0.

How do I use XPath to count the number of nodes with a certain attribute

I can't seem to get an XPath expression to work for my scenario. I want to find all the "Device" nodes that have the type "EndDevice". I'm able to count all the "Device" nodes, and I'm also able to find all "Device" nodes with the "EndDevice" attribute. However, I can't seem to combine them!
count(//Device) //works
//Device[#xsi:type='EndDevice'] //works
count(//Device[#xsi:type='EndDevice']) //doesn't work
If it matters, I'm using XPathBuilder.
I reproduced it using XPathBuilder 2.0.0.4.
However the XPath expression works and evaluates correctly in an online evaluator I tried (http://www.whitebeam.org/library/guide/TechNotes/xpathtestbed.rhtm).
EDIT: Also tried with latest version of Altova XMLspy
input:
<?xml version="1.0"?>
<asdf xmlns:xsi="n/a">
<Device xsi:type='EndDevice'/>
<Device xsi:type='EndDevice'/>
<Device xsi:type='EndDevice'/>
<Device xsi:type='EndDevice'/>
</asdf>
xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xsi="n/a">
<xsl:output indent="yes"/>
<xsl:template match="*">
<output>
<xsl:value-of select="count(//Device[#xsi:type = 'EndDevice'])"/>
</output>
</xsl:template>
</xsl:stylesheet>
output:
<?xml version="1.0" encoding="UTF-8"?>
<output xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xsi="n/a">4</output>
I think it's XPathBuilder thats doing something wrong.
Using the above xml saved into a test.xml and using the tool http://kernowforsaxon.sourceforge.net/
declare namespace xsi="n/a";
count(doc('test.xml')//Device[#xsi:type = "EndDevice"])
Produces the right output.

Format Date of XML Attribute Value Using XSLT

I'm running into an issue with an XSLT Transformation I'm trying to do. In the overall project, I'm working to convert an XML document to a CSV file for a database upload. The problem is the XML sends dates as an attribute value in ISO8601 format (YYYY-MM-DDT00:00:00), but for the database to take it from the CSV file, I need to convert it to MM/DD/YYYY.
Here's an XML Sample:
<GetChanged>
<UserInformation>
<Column Name="id" Value="555555555"/>
<Column Name="name" Value="Kevin"/>
<Column Name="bday" Value="1990-01-01T00:00:00"/>
</UserInformation>
</GetChanged>
Here's the XSLT I'm trying to use:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:csv="csv:csv">
<xsl:output method="text"/>
<xsl:template match="GetChanged">
<!-- header -->
<xsl:text>"id","name","bday"
</xsl:text>
<!-- data rows -->
<xsl:for-each select="UserInformation">
<!-- data cells -->
<xsl:for-each select="Column[#Name='id']">
<xsl:text>"</xsl:text>
<xsl:value-of select="#Value"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:text>,</xsl:text>
<xsl:for-each select="Column[#Name='name']">
<xsl:text>"</xsl:text>
<xsl:value-of select="#Value"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:text>,</xsl:text>
<xsl:for-each select="Column[#Name='bday']">
<xsl:text>"</xsl:text>
<xsl:value-of select="format-date(#Value, '[M01]/[D01]/[Y0001]')"/>
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:if test="position()!=last()">
<xsl:text>,</xsl:text>
</xsl:if>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
However, when I run this through Ruby using Nokogiri, I end up getting an error:
RuntimeError: runtime error: element value-of
XPath evaluation returned no result
Thoughts on what I can do to format this date appropriately?
Thanks in advance!
nokogiri depends on libxslt for XSLT.
In Nokogiri 1.6.0 and later libxml2 and libxslt are bundled with the
gem, but if you want to use the system versions:
(see here for more details: https://github.com/sparklemotion/nokogiri)
libxslt only supports XSLT-1.0
A separate library called libxslt is available implementing XSLT-1.0
for libxml2
(Details see here: http://xmlsoft.org/XSLT.html)
You could work around that by using a solution like this: Convert date from DD-MMM-YYYY to YYYYMMDD format in xslt 1.0
or do some substring/concat like described here: Displaying Date as DD-MM-YYYY within XSLT/XML
A value expressed as YYYY-MM-DDT00:00:00is not a date. Try changing :
<xsl:value-of select="format-date(#Value, '[M01]/[D01]/[Y0001]')"/>
to:
<xsl:value-of select="format-dateTime(#Value, '[M01]/[D01]/[Y0001]')"/>
Note that both functions require an XSLT 2.0 processor. If your processor supports only XSLT 1.0, you can reformat the date using string manipulations:
<xsl:value-of select="substring(#Value, 6, 2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring(#Value, 9, 2)"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="substring(#Value, 1, 4)"/>

Resources