Reputation: 25370
Simplified Question: What's the XPath to select all XML nodes with an attribute that ends with the string "Notification". The first and third nodes in this snippet:
<events>
<event name="CreatedNotification" />
<event name="InfoLog" />
<event name="UpdatedNotification" />
</events>
Detailed Question:
I want to select multiple complexTypes from a xsd schema for binding with JAXB. This works for a single class: OrderStateChangeNotification
<jxb:bindings schemaLocation="apiv2.xsd">
<jxb:bindings node="//xs:complexType[@name='OrderStateChangeNotification']">
<inheritance:implements>com.google.checkout.sdk.notifications.Notification</inheritance:implements>
</jxb:bindings>
</jxb:bindings>
Here is the relevant snippet from the schema schema file:
<xs:complexType name="OrderStateChangeNotification">
<xs:all>
<xs:element name="new-fulfillment-order-state" type="tns:FulfillmentOrderState" />
<xs:element name="new-financial-order-state" type="tns:FinancialOrderState" />
<xs:element name="previous-fulfillment-order-state" type="tns:FulfillmentOrderState" />
<xs:element name="previous-financial-order-state" type="tns:FinancialOrderState" />
<xs:element name="reason" type="xs:string" minOccurs="0" />
<xs:element name="timestamp" type="xs:dateTime" />
<xs:element name="google-order-number" type="xs:token" />
<xs:element name="order-summary" type="tns:OrderSummary" minOccurs="0" />
</xs:all>
<xs:attribute name="serial-number" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="ChargeAmountNotification">
<xs:all>
<xs:element name="timestamp" type="xs:dateTime" />
<xs:element name="latest-charge-amount" type="tns:Money" />
<xs:element name="latest-charge-fee" type="tns:FeeStructure" minOccurs="0" />
<xs:element name="total-charge-amount" type="tns:Money" />
<xs:element name="latest-promotion-charge-amount" type="tns:Money" minOccurs="0" />
<xs:element name="google-order-number" type="xs:token" />
<xs:element name="order-summary" type="tns:OrderSummary" minOccurs="0" />
</xs:all>
<xs:attribute name="serial-number" type="xs:string" use="required" />
</xs:complexType>
I want the binding to apply to all notification objects. They all end in with "Notification"
I've tried changing the XPath from
//xs:complexType[@name='OrderStateChangeNotification']
to
//xs:complexType[substring(name(), string-length(name()) - 12) = 'Notification']
but it didn't work.
Another approach is to try and select all nodes with the children "order-summary" and "serial-number" as I know only Notification objects have these.
UPDATE: The solution by @Lee Greco correctly selectes the nodes I wanted, but unfortunatly, the inheritance plugin is not compatible with multiple nodes:
[ERROR] XPath evaluation of "//xs:complexType[substring(@name, string-length(@name)-string-length('Notification')+1)='Notification']" results in too many (8) target nodes
I ended up just enumerating them separately.
Upvotes: 11
Views: 16809
Reputation: 386
I end up with a similar problem "too many target nodes(3)" however could not find any answer on any of the sites...Posting the solution which I found after lots of trail and error...Basic idea to solve "too many target nodes(3)" is to give complete XPATH of the node which is multiple in your XSD.
Below is my XSD:
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="document">
<xs:complexType>
<xs:sequence>
<xs:element name="asset">
<xs:complexType>
<xs:sequence>
<xs:element name="attribute" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="string" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="value" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="date" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="value" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="array" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="struct" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="field" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="integer" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:byte" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="assetreference" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="type"/>
<xs:attribute type="xs:long" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="integer" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:long" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="file" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="name" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="integer" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:short" name="value"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute type="xs:long" name="id"/>
<xs:attribute type="xs:string" name="type"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
and below is the JAXB binding file which is working for above XSD:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.1">
<bindings schemaLocation= "../assetproduct.xsd" version="1.0">
<!-- Customise the package name
<schemaBindings>
<package name="com.example.schema"/>
</schemaBindings> -->
<!-- rename the value element -->
<bindings node="//xs:element[@name='document']">
<bindings node="//xs:element[@name='asset']">
<bindings node="//xs:element[@name='attribute']">
<bindings node="//xs:element[@name='string']">
<bindings node=".//xs:attribute[@name='value']">
<property name="ValueAttribute"/>
</bindings>
</bindings>
<bindings node="//xs:element[@name='date']">
<bindings node=".//xs:attribute[@name='value']">
<property name="ValueAttribute"/>
</bindings>
</bindings>
<bindings node="//xs:element[@name='array']">
<bindings node=".//xs:element[@name='struct']">
<bindings node=".//xs:element[@name='field']">
<bindings node=".//xs:element[@name='integer']/xs:complexType">
<bindings node=".//xs:attribute[@name='value']">
<property name="ValueAttribute"/>
</bindings>
</bindings>
<bindings node=".//xs:element[@name='assetreference']">
<bindings node=".//xs:attribute[@name='value']">
<property name="ValueAttribute"/>
</bindings>
</bindings>
</bindings>
</bindings>
</bindings>
<bindings node=".//xs:element[@name='array']/xs:complexType/xs:sequence/xs:element[@name='integer']">
<bindings node=".//xs:attribute[@name='value']">
<property name="ValueAttribute"/>
</bindings>
</bindings>
<bindings node="//xs:element[@name='attribute']/xs:complexType/xs:sequence/xs:element[@name='integer']">
<bindings node=".//xs:attribute[@name='value']">
<property name="ValueAttribute"/>
</bindings>
</bindings>
</bindings>
</bindings>
</bindings>
</bindings>
</bindings>
Upvotes: 0
Reputation: 2080
I had the same problem. I found out there was a multiple
attribute that was used by XJC to allow multiple node match.
I also wanted the binding to apply to every schema locations. xs:anyURI
did not work but I found a way to do it using the *
token. I added the required="false"
attribute in order to ignore schemas that does not contain any match.
<jxb:bindings schemaLocation="*">
<jxb:bindings node="//xs:complexType[substring(name(), string-length(name()) - 12) = 'Notification']" multiple="true" required="false">
<inheritance:implements>com.google.checkout.sdk.notifications.Notification</inheritance:implements>
</jxb:bindings>
</jxb:bindings>
Edit: I posted this answer without reading the comments of the question. Sorry for that. I'm using maven plugin org.codehaus.mojo:jaxb2-maven-plugin:1.5
with XJC plugin org.jvnet.jaxb2_commons:jaxb2-basics-project:0.6.4
and it seems to work like this...
Upvotes: 7
Reputation: 743
With the
//xs:complexType[substring(name(), string-length(name()) - 12) = 'Notification']
expression you're asking for all elements where the element name ends in 'Notification'. You really want to ask for all elements with a name attribute that ends in 'Notification'.
Try this instead:
//xs:complexType[substring(@name, string-length(@name)-string-length("Notification")+1)="Notification"]
Upvotes: 5