www.espertech.comDocumentation
This section provides information for using org.w3c.dom.Node
XML to represent events.
For NEsper .NET also see Section J.9, “.NET XML Events”.
Events can be represented as org.w3c.dom.Node
instances and send into the runtime via the sendEventXMLDOM
method on EPEventService
or via EventSender
. Please note that either configuration or create xml schema
with annotations are required so the event type name and root element name is known. See Section 17.4.8, “Events Represented by org.w3c.dom.Node”.
If a XML schema document (XSD file) can be made available as part of the configuration or as part of create xml schema
, then the compiler and runtime can read the schema and appropriately present event type metadata and validate statements that use the event type and its properties. See Section I.2, “Schema-Provided XML Events”.
When no XML schema document is provided, XML events can still be queried, however the return type and return values of property expressions are string-only and no event type metadata is available other than for explicitly configured properties. See Section I.3, “No-Schema-Provided XML Events”.
In all cases the compiler and runtime allow you to configure explicit XPath expressions as event properties. You can specify arbitrary XPath functions or expressions and provide a property name and type by which result values will be available for use in statements. See Section I.4, “Explicitly-Configured Properties”.
Nested, mapped and indexed event properties are also supported in expressions against org.w3c.dom.Node
events. Thus XML trees can conveniently be interrogated via the property expression syntax.
Only one event type per root element name may be configured.
This section uses the following XML document as an example:
<?xml version="1.0" encoding="UTF-8"?> <Sensor xmlns="SensorSchema"> <ID>urn:epc:1:4.16.36</ID> <Observation Command="READ_PALLET_TAGS_ONLY"> <ID>00000001</ID> <Tag> <ID>urn:epc:1:2.24.400</ID> </Tag> <Tag> <ID>urn:epc:1:2.24.401</ID> </Tag> </Observation> </Sensor>
The schema for the example is:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Sensor"> <xs:complexType> <xs:sequence> <xs:element name="ID" type="xs:string"/> <xs:element ref="Observation" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Observation"> <xs:complexType> <xs:sequence> <xs:element name="ID" type="xs:string"/> <xs:element ref="Tag" maxOccurs="unbounded" /> </xs:sequence> <xs:attribute name="Command" type="xs:string" use="required" /> </xs:complexType> </xs:element> <xs:element name="Tag"> <xs:complexType> <xs:sequence> <xs:element name="ID" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
If you have a XSD schema document available for your XML events, the compiler and runtime can interrogate the schema. The benefits are:
New statements that refer to event properties are validated against the types provided in the schema.
Event type metadata becomes available for retrieval as part of the EventType
interface.
The compiler reads a XSD schema file from an URL you provide. Make sure files imported by the XSD schema file can also be resolved.
The configuration and create xml schema
accept a schema URL. This is a sample code snippet to determine a schema URL from a file in classpath:
URL schemaURL = this.getClass().getClassLoader().getResource("sensor.xsd"); // For NEsper .NET use C# ResourceManager class for loading resources
Here is a sample use of the configuration API, please see Chapter 17, Configuration for further examples.
ConfigurationCommonEventTypeXMLDOM sensorcfg = new ConfigurationCommonEventTypeXMLDOM(); sensorcfg.setRootElementName("Sensor"); sensorcfg.setSchemaResource(schemaURL.toString()); Configuration configuration = new Configuration(); configuration.getCommon().addEventType("SensorEvent", sensorcfg);
Here is a sample use of create xml
schema.
@XMLSchema(rootElementName='Sensor', schemaResource='some url value here') create xml schema SensorEvent()
There does not need to be a root element name. The sendEventXMLDOM(org.w3c.Node node, String eventTypeName)
method accepts the event type name. An EventSender
is a useful alternative method
for sending events if the type lookup based on the root or document element name is not desired.
After adding the event type, you may create statements and send events. Next is a sample statement:
select ID, Observation.Command, Observation.ID, Observation.Tag[0].ID, Observation.Tag[1].ID from SensorEvent
As you can see from the example above, property expressions can query property values held in the XML document's elements and attributes.
There are multiple ways to obtain a XML DOM document instance from a XML string. The next code snippet shows how to obtain a XML DOM org.w3c.Document
instance:
InputSource source = new InputSource(new StringReader(xml)); DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); Document doc = builderFactory.newDocumentBuilder().parse(source);
Send the org.w3c.Node
or Document
object into the runtime for processing:
runtime.getEventService().sendEventXMLDOM(doc, "SensorEvent");
By default, property expressions such as Observation.Tag[0].ID
are evaluated by a fast DOM-walker implementation provided by EPL. This DOM-walker implementation is not namespace-aware.
Should you require namespace-aware traversal of the DOM document, you must set the xpath-property-expr
configuration option to true (default is false). This flag causes the compiler and runtime to generate namespace-aware XPath
expressions from each property expression instead of the DOM-walker, as described next. Setting the xpath-property-expr
option to true requires that you also configure namespace prefixes as described below.
When matching up the property names with the XSD schema information, the compiler determines whether the attribute or element provides values. The algorithm checks attribute names first followed by element names. It takes the first match to the specified property name.
By setting the xpath-property-expr
option the compiler rewrites each property expression as an XPath expression, effectively handing the evaluation over to the underlying XPath implementation
available from classpath. Most JVM have a built-in XPath implementation and there are also optimized, fast implementations such as Jaxen that can be used as well.
Set the xpath-property-expr
option if you need namespace-aware document traversal, such as when your schema mixes several namespaces and element names are overlapping.
The below table samples several property expressions and the XPath expression generated for each, without namespace prefixes to keep the example simple:
Table I.1. Property Expression to XPath Expression
Property Expression | Equivalent XPath |
---|---|
Observeration.ID | /Sensor/Observation/ID |
Observeration.Command | /Sensor/Observation/@Command |
Observeration.Tag[0].ID | /Sensor/Observation/Tag[position() = 1]/ID |
For mapped properties that are specified via the syntax name('key')
, the algorithm looks for an attribute by name id
and generates a XPath expression as mapped[@id='key']
.
Finally, here is an example that includes all different types of properties and their XPath expression equivalent in one property expression:
select nested.mapped('key').indexed[1].attribute from MyEvent
The equivalent XPath expression follows, this time including n0
as a sample namespace prefix:
/n0:rootelement/n0:nested/n0:mapped[@id='key']/n0:indexed[position() = 2]/@attribute
All elements that are unbound or have max occurs greater then 1 in the XSD schema are represented as indexed properties and require an index for resolution.
For example, the following is not a valid property expression in the sample Sensor document: Observeration.Tag.ID
. As no index is provided for Tag
, the property expression is not valid.
Repeated elements within a parent element in which the repeated element is a simple type also are represented as an array.
Consider the next XML document:
<item> <book sku="8800090"> <author>Isaac Asimov</author> <author>Robert A Heinlein</author> </book> </item>
Here, the result of the expression book.author
is an array of type String and the result of book.author[0]
is a String value.
Dynamic properties are not validated against the XSD schema information and their result value is always org.w3c.Node
. You may use a user-defined function to process dynamic properties returning Node
. As an alternative consider using an explicit property.
An example dynamic property is Origin?.ID
which will look for an element by name Origin
that contains an element or attribute node by name LocationCode
:
select Origin?.LocationCode from SensorEvent
When providing a XSD document, the default configuration allows to transpose property values that are themselves complex elements, as defined in the XSD schema, into a new stream. This behavior can be controlled via the flag auto-fragment
.
For example, consider the next statement:
insert into ObservationStream select ID, Observation from SensorEvent
The Observation
as a property of the SensorEvent
gets itself inserted into a new stream by name ObservationStream
. The ObservationStream
thus consists of a string-typed ID
property and a complex-typed property named Observation
, as described in the schema.
A further statement can use this stream to query:
select Observation.Command, Observation.Tag[0].ID from ObservationStream
Before continuing the discussion, here is an alternative syntax using the wildcard-select, that is also useful:
insert into TagListStream select ID as sensorId, Observation.* from SensorEvent
The new TagListStream
has a string-typed ID
and Command
property as well as an array of Tag
properties that are complex types themselves as defined in the schema.
Next is a sample statement to query the new stream:
select sensorId, Command, Tag[0].ID from TagListStream
Please note the following limitations:
The XPath standard prescribes that XPath expressions against org.w3c.Node
are evaluated against the owner document of the Node
. Therefore XPath is not relative to the current node but absolute against each node's owner document. Since the compiler and runtime do not create new document instances for transposed nodes, transposing properties is not possible when the xpath-property-expr
flag is set.
Complex elements that have both simple element values and complex child elements are not transposed. This is to ensure their property value is not hidden. Use an explicit XPath expression to transpose such properties.
EPL automatically registers a new event type for transposed properties. It generates the type name of the new XML event type from the XML event type name and the property names used in the expression. The synposis is type_name.property_name[.property_name...]. The type name can be looked up, for example for use with EventSender
or can be created in advance.
An EventSender
sends events into the runtime for a given type, saving a type lookup based on element name.
This brief example sends an event via EventSender
:
EventSender sender = epRuntime.getEventSender("SensorEvent"); sender.sendEvent(node);
The XML DOM event sender checks the root element name before processing the event. Use the event-sender-validates-root
setting to disable validation. This forces the runtime to process XML documents according to any predefined type without validation of the root element name.
The compiler schema interrogation is based on the Xerces distribution packaged into Sun Java runtimes. Your application may not replace the JRE's Xerces version and use XML schemas, unless your application sets the DOM implementation registry as shown below before loading the configuration:
System.setProperty(DOMImplementationRegistry.PROPERTY, "com.sun.org.apache.xerces.internal.dom.DOMXSImplementationSourceImpl");
Without a schema document a XML event may still be queried. However there are important differences in the metadata available without a schema document and therefore the property expression results. These differences are outlined below.
All property expressions against a XML type without schema are assumed valid. There is no validation of the property expression other than syntax validation. At runtime, property expressions return string-type values or null
if the expression did not
yield a matching element or attribute result.
When asked for property names or property metadata, a no-schema type returns empty array.
In all other aspects the type behaves the same as the schema-provided type described earlier.
Regardless of whether or not you provide a XSD schema for the XML event type, you can always fall back to configuring explicit properties that are backed by XPath expressions.
For further documentation on XPath, please consult the XPath standard or other online material. Consider using Jaxen or Apache Axiom, for example, to provide faster XPath evaluation then your Java VM built-in XPath provider may offer.
Shown below is an example configuration that adds an explicit property backed by a XPath expression and that defines namespace prefixes:
ConfigurationCommonEventTypeXMLDOM sensorcfg = new ConfigurationCommonEventTypeXMLDOM(); sensorcfg.addXPathProperty("countTags", "count(/ss:Sensor/ss:Observation/ss:Tag)", XPathConstants.NUMBER); sensorcfg.addNamespacePrefix("ss", "SensorSchema"); sensorcfg.setRootElementName("Sensor"); Configuration configuration = new Configuration(); configuration.getCommon().addEventType("SensorEvent", sensorcfg);
Shown below is an example create xml schema
:
@XMLSchema(rootElementName='Sensor') @XMLSchemaField(name='countTags', xpath='count(/ss:Sensor/ss:Observation/ss:Tag', type='number') @XMLSchemaNamespacePrefix(prefix='ss', namespace='SensorSchema') create xml schema SensorEvent();
The countTags
property is now available for querying:
select countTags from SensorEvent
The XPath expression count(...)
is a XPath built-in function that counts the number of nodes, for the example document the result is 2
.
The compiler and runtime can parse or cast the result of your XPath expression to the desired type. Your property configuration provides the type to cast to, like this:
sensorcfg.addXPathProperty("countTags", "count(/ss:Sensor/ss:Observation/ss:Tag)", XPathConstants.NUMBER, "int");
The type supplied to the property configuration must be one of the built-in types. Arrays of built-in type are also possible, requiring the XPathConstants.NODESET
type returned by your XPath expression, as follows:
sensorcfg.addXPathProperty("idarray", "//ss:Tag/ss:ID", XPathConstants.NODESET, "String[]");
This EPL snippet is the equivalent of above for use with create xml schema
:
@XMLSchemaField(name='countTags', xpath='count(/ss:Sensor/ss:Observation/ss:Tag)', type='number', castToType='int') @XMLSchemaField(name='idarray', xpath='//ss:Tag/ss:ID)', type='nodeset', castToType='string[]')
The XPath expression //ss:Tag/ss:ID
returns all ID nodes under a Tag node, regardless of where in the node tree the element is located. For the example document the result is 2
array elements urn:epc:1:2.24.400
and urn:epc:1:2.24.40
.
An explicit property may return XPathConstants.NODE
or XPathConstants.NODESET
and can provide the event type name of a pre-configured event type for the property. The method name to add such properties is addXPathPropertyFragment
.
This code snippet adds two explicit properties and assigns an event type name for each property:
sensorcfg.addXPathPropertyFragment("tagOne", "//ss:Tag[position() = 1]", XPathConstants.NODE, "TagEvent"); sensorcfg.addXPathPropertyFragment("tagArray", "//ss:Tag", XPathConstants.NODESET, "TagEvent");
This EPL snippet is the equivalent of above for use with create xml schema
:
@XMLSchemaField(name='tagOne', xpath='//ss:Tag[position() = 1]', type='node', eventTypeName='TagEvent') @XMLSchemaField(name='tagArray', xpath='//ss:Tag', type='nodeset', eventTypeName='TagEvent')
The configuration or annotation above references the TagEvent
event type. This type must also be configured or created. Prefix the root element name with "//" to cause the lookup to search the nested schema elements for the definition of the type:
ConfigurationCommonEventTypeXMLDOM tagcfg = new ConfigurationCommonEventTypeXMLDOM(); tagcfg.setRootElementName("//Tag"); tagcfg.setSchemaResource(schemaURL); Configuration configuration = new Configuration(); configuration.getCommon().addEventType("TagEvent", tagcfg);
The tagOne
and tagArray
properties are now ready for selection and transposing to further streams:
insert into TagOneStream select tagOne.* from SensorEvent
Select from the new stream:
select ID from TagOneStream
An example with indexed properties is shown next:
insert into TagArrayStream select tagArray as mytags from SensorEvent
Select from the new stream:
select mytags[0].ID from TagArrayStream
Further information on using create xml schema
with XMLSchema
, XMLSchemaNamespacePrefix
and XMLSchemaField
can be found at Section 17.4.8, “Events Represented by org.w3c.dom.Node”.
The create xml schema
statement does not allow specifying event properties.
The create xml schema
statement does not support copyfrom
and inherits
.