I use an XML Schema Definition and JAXB to generate Java classes with proper @XmlElement
or @XmlRootElement
annotations.
Since the schema has some deep nesting in it (not my choice), I'd rather use jxpath
to access deeply buried classes using an XPath (rather than cumbersome daisy-chain of .getThat()
and that != null
).
The problem is that some of the XML element names contain dashes, e.g. foo-bar
. When I try to access elements using org.apache.jxpath
, I need to rewrite my XPath so that such names are camel-cased instead (fooBar
) like the name of the actual Java objects. Is there any way to tell jxpath
to find the elements using the XPath corresponding to the XML element names (instead of the camel-cased Bean names)?
I think it is related to this question, however in my case I don't actually case what kind of tricks and decorations are used on the auto-generated classes, as long as xjc can do it.
Here is a simple example to illustrate the issue.
First, a small XSD file:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="record">
<xs:complexType>
<xs:sequence>
<xs:element name="foo-bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Compile it...
xjc -p org.pd.jx example.xsd
Here is the xjc-generated Record.java
class (minus comments):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"fooBar"})
@XmlRootElement(name = "record")
public class Record {
@XmlElement(name = "foo-bar", required = true)
protected String fooBar;
public String getFooBar() {return fooBar;}
public void setFooBar(String value) {this.fooBar = value;}
}
Then, trying to access the data via jxpath
(in practice I have to deal with lots of deeply nested classes), one can see below that the correct XPath ("foo-bar"
) doesn't work, but a camel-cased version does.
Record record = new Record();
record.setFooBar("hello world");
JXPathContext context = JXPathContext.newContext(record);
context.setLenient(true);
String a = (String)context.getValue("foo-bar", String.class); // is null
String b = (String)context.getValue("fooBar", String.class); // "hello world"
I believe JXPath operates on an objects properties and not the XML elements they correspond to. I do not believe that JXPath parses any of the JAXB metadata so it wouldn't know the XML nodea you have mapped. What you are seeing appears to be the expected behaviour.