java.lang.RuntimeException: Invalid conversion from 'node-set' to 'org.apache.xmlbeans.impl.store.Xobj$DocumentXobj'
I see many frustrated bloggers posting questions. After my own long frustrating hours, i concluded it's an OSB bug. Good news is i also figured out a solution.
At the core, the issue is OSB passes in the parameter to XLST as org.apache.xmlbeans.impl.store.Xobj$DocumentXobj object (with the exception if the parameter is a simple string). But XSLT is expecting a NodeList.
Here is a quick solution. Compile this class, jar it up and copy it to your domain/lib directory:
package org.example.xslt;
import org.w3c.dom.NodeList;
import org.w3c.dom.Node;
public class XObjUtil
{
public NodeList getNodeList(Object o)
{ System.out.println("### getNodeList o class name="+o.getClass().getName());
org.w3c.dom.Document xo = (org.w3c.dom.Document)o;
Node n = (Node) xo;
NodeList nl = n.getChildNodes();
return nl;
// lazy way: return (((org.w3c.dom.Document)o)).getChildNodes();
}
}
Here is my cheap script to compile, jar and copy the file:
javac -d . XObjUtil.java
del myxlstext.jar
jar cvf myxlstext.jar org
copy myxlstext.jar C:\Oracle\Middleware\user_projects\domains\osbserver\lib
On the OSB side, here is the XSLT what will parse the input parameter:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:client="http://xmlns.oracle.com/JCA_ResourceAdapter/foo/BPELProcess1"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:XObj="http://www.oracle.com/XSL/Transform/java/org.example.xslt.XObjUtil"
exclude-result-prefixes="xsl client ">
<xsl:param name="car" />
<xsl:template match="/">
<client:process>
<xsl:variable name="x" select="XObj:new()" />
<xsl:variable name="obj" select="XObj:getNodeList($x, $car)" />
<client:input>
<xsl:value-of select="$obj/client:car1" />
</client:input>
<client:foo1>
<xsl:value-of select="$obj/client:car2" />
</client:foo1>
<client:foo2>
<xsl:value-of select="/client:barElem/client:bar2" />
</client:foo2>
</client:process>
</xsl:template>
</xsl:stylesheet>
My foo/bar/car sample is based on this cheap XSD
<?xml version="1.0" encoding="UTF-8" ?>
<schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://xmlns.oracle.com/JCA_ResourceAdapter/foo/BPELProcess1"
xmlns:this="http://xmlns.oracle.com/JCA_ResourceAdapter/foo/BPELProcess1" xmlns="http://www.w3.org/2001/XMLSchema">
<complexType name="fooType">
<sequence>
<element name="input" type="string"/>
<element name="foo1" type="string"/>
<element name="foo2" type="string"/>
</sequence>
</complexType>
<complexType name="barType">
<sequence>
<element name="input" type="string"/>
<element name="bar1" type="string"/>
<element name="bar2" type="string"/>
</sequence>
</complexType>
<complexType name="carType">
<sequence>
<element name="input" type="string"/>
<element name="car1" type="string"/>
<element name="car2" type="string"/>
</sequence>
</complexType>
<element name="process" type="this:fooType"/>
<element name="carElem" type="this:carType"/>
<element name="barElem" type="this:barType"/>
<element name="processResponse">
<complexType>
<sequence>
<element name="result" type="string"/>
</sequence>
</complexType>
</element>
</schema>
Here is a sample output from the OSB test console:
client:process | xmlns:client="http://xmlns.oracle.com/JCA_ResourceAdapter/foo/BPELProcess1"xmlns:XObj="http://www.oracle.com/XSL/Transform/java/org.example.xslt.XObjUtil"> |
<client:input>car18</client:input> |
<client:foo1>car29</client:foo1> |
<client:foo2>bar23</client:foo2> |
</client:process> |
One interesting fact is this sample shows you a cheap way of extending XSLT without a full blown Xpath function project, see here http://yuanmengblog.blogspot.com/2013/04/break-comma-separated-string-into-array.html
BTW, very importantly, SOA and OSB uses different XSLT framework. OSB uses more org.w3 XML, SOA use "Oracle" own XML stuff. When SOA invokes XSLT, it passes in the parameter as type oracle.xml.parser.v2.XMLDocumentFragment, if ever want to play with that, the conversion is this:
public NodeList getNodeList(oracle.xml.parser.v2.XMLDocumentFragment o)
{
org.w3c.dom.NodeList nl = ((org.w3c.dom.Node)o).getChildNodes();
return nl;
}
Two other things you can explore:
1. instead of tossing the jar file into domain/lib directory, try if you can merely upload the jar to the proxy folder in OSB, treats it like a java callout jar. If that works, then you don't need to reboot OSB when change your jar file.
2. implement this as an Xpath function, then your JDev XSLT editor can pick it up. Of course, your XSLT syntax will be modified slightly as well. Have fun!
Hi, this is not a bug in OSB, has to do with the xsl processor used in this case Xalan, if you use an editor like Oxygen and execute the test really get the same errror.
ReplyDeleteSeverity: fatal
Description: org.apache.xpath.objects.XString can not be cast to org.apache.xpath.objects.XNodeSet - org.apache.xpath.objects.XString can not be cast to org.apache.xpath.objects.XNodeSet
at the end the solution you pose is very viable
For example when I use saxon-EE 9.4.0.4 this expect a node()
Hi Yuan
ReplyDeleteYour java method signarue:
public NodeList getNodeList(Object o)
The XSLT call:
Isn't there a parameter mismatch?
This comment has been removed by the author.
DeleteHi, the solution is here
ReplyDeletehttp://rickymax.wordpress.com/2014/12/15/how-work-with-xslt-input-parameters-in-oracle-service-bus/