I have this XML:
<workflow>
<initial-actions>
<action id="1" name="Create"/>
</initial-actions>
</workflow>
I generated the Java classes using JAXB and successfully unmarshalled it in variable "wf".
Then invoking JXPath:
String xpath = "initialActions/action[@name='Create']";
JXPathContext context = JXPathContext.newContext(wf);
Object v = context.getValue(xpath);
JXPath would complain that no value is found. But if I change the selector to id:
String xpath = "initialActions/action[@id='1']/@name";
JXPathContext context = JXPathContext.newContext(wf);
Object v = context.getValue(xpath);
Then v contains "Create".
Why @name selector finds nothing?
Edit: This is the Action class generated by JAXB:
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element ref="{}meta" maxOccurs="unbounded" minOccurs="0"/>
* <element ref="{}restrict-to" minOccurs="0"/>
* <element ref="{}validators" minOccurs="0"/>
* <element ref="{}pre-functions" minOccurs="0"/>
* <element ref="{}results"/>
* <element ref="{}post-functions" minOccurs="0"/>
* </sequence>
* <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="view" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="auto">
* <simpleType>
* <restriction base="{http://www.w3.org/2001/XMLSchema}NMTOKEN">
* <enumeration value="TRUE"/>
* <enumeration value="FALSE"/>
* <enumeration value="true"/>
* <enumeration value="false"/>
* </restriction>
* </simpleType>
* </attribute>
* <attribute name="finish">
* <simpleType>
* <restriction base="{http://www.w3.org/2001/XMLSchema}NMTOKEN">
* <enumeration value="TRUE"/>
* <enumeration value="FALSE"/>
* <enumeration value="true"/>
* <enumeration value="false"/>
* </restriction>
* </simpleType>
* </attribute>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"meta",
"restrictTo",
"validators",
"preFunctions",
"results",
"postFunctions"
})
@XmlRootElement(name = "action")
public class Action
implements WorkflowPart
{
protected List<Meta> meta;
@XmlElement(name = "restrict-to")
protected RestrictTo restrictTo;
protected Validators validators;
@XmlElement(name = "pre-functions")
protected PreFunctions preFunctions;
@XmlElement(required = true)
protected Results results;
@XmlElement(name = "post-functions")
protected PostFunctions postFunctions;
@XmlAttribute(name = "id", required = true)
protected String id;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "view")
protected String view;
@XmlAttribute(name = "auto")
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
protected String auto;
@XmlAttribute(name = "finish")
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
protected String finish;
/**
* Gets the value of the meta property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the meta property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getMeta().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Meta }
*
*
*/
public List<Meta> getMeta() {
if (meta == null) {
meta = new ArrayList<Meta>();
}
return this.meta;
}
/**
* Gets the value of the restrictTo property.
*
* @return
* possible object is
* {@link RestrictTo }
*
*/
public RestrictTo getRestrictTo() {
return restrictTo;
}
/**
* Sets the value of the restrictTo property.
*
* @param value
* allowed object is
* {@link RestrictTo }
*
*/
public void setRestrictTo(RestrictTo value) {
this.restrictTo = value;
}
/**
* Gets the value of the validators property.
*
* @return
* possible object is
* {@link Validators }
*
*/
public Validators getValidators() {
return validators;
}
/**
* Sets the value of the validators property.
*
* @param value
* allowed object is
* {@link Validators }
*
*/
public void setValidators(Validators value) {
this.validators = value;
}
/**
* Gets the value of the preFunctions property.
*
* @return
* possible object is
* {@link PreFunctions }
*
*/
public PreFunctions getPreFunctions() {
return preFunctions;
}
/**
* Sets the value of the preFunctions property.
*
* @param value
* allowed object is
* {@link PreFunctions }
*
*/
public void setPreFunctions(PreFunctions value) {
this.preFunctions = value;
}
/**
* Gets the value of the results property.
*
* @return
* possible object is
* {@link Results }
*
*/
public Results getResults() {
return results;
}
/**
* Sets the value of the results property.
*
* @param value
* allowed object is
* {@link Results }
*
*/
public void setResults(Results value) {
this.results = value;
}
/**
* Gets the value of the postFunctions property.
*
* @return
* possible object is
* {@link PostFunctions }
*
*/
public PostFunctions getPostFunctions() {
return postFunctions;
}
/**
* Sets the value of the postFunctions property.
*
* @param value
* allowed object is
* {@link PostFunctions }
*
*/
public void setPostFunctions(PostFunctions value) {
this.postFunctions = value;
}
/**
* Gets the value of the id property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getId() {
return id;
}
/**
* Sets the value of the id property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setId(String value) {
this.id = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the view property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getView() {
return view;
}
/**
* Sets the value of the view property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setView(String value) {
this.view = value;
}
/**
* Gets the value of the auto property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getAuto() {
return auto;
}
/**
* Sets the value of the auto property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setAuto(String value) {
this.auto = value;
}
/**
* Gets the value of the finish property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getFinish() {
return finish;
}
/**
* Sets the value of the finish property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setFinish(String value) {
this.finish = value;
}
}
Edit 2: This XPath works (remove @ in front of name):
String xpath = "initialActions/action[name='Create']";
And these two produce the same value:
String xpath = "initialActions/action[name='Create']/@name";
String xpath2 = "initialActions/action[name='Create']/name";
While name is an attribute in the XML, in the JAXB generated class it is just a normal field.
JXPath documentation says,
For JavaBeans and Maps the "attribute::" axis is interpreted the same as the "child::" axis.
which explains why both @name and name work to retrieve the value.
But then when would you use @attributeName in JXPath? Is it only needed if you use XMLDocumentContainer?