|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.jbpm.xml.Parser
public class Parser
makes typical usage of JAXP more convenient, adds a binding framework, entity resolution and error handling.
This is a base parser for the common pattern where first JAXP is used to parse xml into a Document Object Model (DOM), and then, this DOM is examined to build a domain model object. The main purpose of this parser is to serve as a base class for implementing such parsers and to provide a more convenient API for working with JAXP.
A Parser
is a thread safe object. For each parse operation, a
new Parse
object is created with method createParse()
.
Then the parse object is used to specify the input source, execute the
parse operation and extract the results.
Binding
s capture parsing of a certain element type. This way,
the parser becomes more modular and customizable.
Entities
are schema's that specify the grammar of the
XML files that are parsed by the parser.
Parsers can be customized by inheritance (that will be covered below), but a parser can also be used as is:
1 | static Parser parser = new Parser(); 2 | 3 | void someMethod() { 4 | MyDomainObject mdo = (MyDomainObject) parser 5 | .createParse() 6 | .setString(myXmlString) 7 | .execute() 8 | .checkProblems() 9 | .getDocumentObject(); 10 | }
line 1 shows that a single parser can be used for all threads as the parser is maintained in a static member field.
line 5 shows that a new parse operation is always started with
the createParse()
operation. The Parse
object that is
returned will maintain all data that is related to that single parse
operation.
line 6 shows how a simple XML string can be provided as the input
source for the parse operation. Alternative methods to specify the input
source are Parse.setFile(java.io.File)
,
Parse.setInputStream(java.io.InputStream)
,
Parse.setInputSource(InputSource)
,
Parse.setUrl(java.net.URL)
and
Parse.setStreamSource(StreamSource)
.
line 7 shows how the execution of the parse is performed. The input source will be read, the resulting Document Object Model (DOM) will be walked and potentially problems are produced in the parse.
line 8 shows how an exception can be thrown in case of an error.
The parse execution itself tries to keep parsing as much as possible to
provide the developer with as much feedback as possible in one parse cycle.
The problems
are silently captured in the parse
object. If an exception is thrown by
#Parse#checkProblems(String, Parse)
, it will contain a report of
all the parsing problems. Alternatively, the problems
in the parse object
could be examined directly without the need for an exception.
line 9 shows how the result of the parse operation is extracted from the parse object.
Bindings are the link between a certain type of element in your XML document and the corresponding java object in your domain model.
A parser can be configured with a set of Binding
s. Each Binding
knows how to transform a dom element of a given tagName to the corresponding Java
object. Bindings
has a notion of binding categories. For example, nodes
and actions can be seen as different categories in jPDL.
The purpose of bindings is to make certain elements in the parsing configurable. E.g. in jPDL, the main structure of the document is fixed. But node types can be added dynamically.
The current Bindings
implementation only supports matching of an
element with a Binding
based on tagName. If you want to take other things
into account (e.g. when you want to differentiate between elements of the same
tagName with a different attribute value), you can create a specialized
Bindings
class.
Bindings are added by tagName, but they have to be looked up by element. That is
to support more specialized bindings implementations that match an element with a
binding on more information then just the tagName. In that case, a specialized subclass of
Binding
should be created and the method getBinding(Element, String)
and
constructor Bindings.Bindings(Bindings)
should be provided
with the more specialized matching behaviour.
When implementing Binding
s, you might want to make use of the
contextual object stack that is provided on the Parse
. The
Binding
implementations can maintain Java objects on that stack
that are being created.
E.g. you could push the ProcessDefinition element onto the object stack while it is being parsed like this:
public class MyProcessBinding implements Binding { public Object parse(Element element, Parse parse, Parser parser) { // instantiate the object for this binding MyProcess myProcess = new MyProcess(); // collect all the child elements of element Listelements = XmlUtil.elements(element); // push my processDefinition onto the object stack parse.pushObject(myProcess); try { for (Element nodeElement: elements) { // parse the child elements with the bindings in category "node" parseElement(nodeElement, parse, "node"); } } finally { // make sure my processDefinition is popped. parse.popObject(); } return myProcess; } }
Then, node bindings might access the processDefinition like this:
public class MyNodeBinding implements Binding { public Object parse(Element element, Parse parse, Parser parser) { // instantiate the object for this binding MyNode myNode = new MyNode(); // add the node to the processDefinition MyProcess myProcess = parse.findObject(MyProcess.class); myProcess.addNode(myNode); myNode.setMyProcess(myProcess); return myNode; } }
A parser implementation will typically have a static Bindings object that
is leveraged in all parser objects. To customize bindings for a such a parser
be sure to make a deep copy with Bindings.Bindings(Bindings)
before
you start adding more bindings to the specialized parser. Otherwise the
base parser's bindings will be updated as well.
This parser is build for inheritance.
Overriding method parseDocumentElement(Element, Parse)
can be an easy
way to start writing your own logic on walking the Document Object Model (DOM).
Such customizations can still be combined with the usage of
bindings.
A parser can be configured with a set of entities with the
addEntity(String, Entity)
method. The UrlEntity
has
a convenience method to build entities from resources
UrlEntity.UrlEntity(String, ClassLoader)
.
When a document builder is created, the default implementation of the
#setEntityResolver(DocumentBuilder)
will set this parser as the entity resolver.
The implementation method of EntityResolver
(resolveEntity(String, String)
will use the added Entity
s to try and find a match based on the
publicId. If one is found, the Entity
inputSource is returned, otherwise
the systemId is used.
This class is intended to be used with aggregation as well as inheritence.
Field Summary | |
---|---|
protected Bindings |
bindings
|
protected java.lang.ClassLoader |
classLoader
|
protected javax.xml.parsers.DocumentBuilderFactory |
documentBuilderFactory
|
protected java.util.Map<java.lang.String,Entity> |
entities
|
Constructor Summary | |
---|---|
Parser()
the default parser |
|
Parser(Bindings bindings)
creates a new Parser with bindings that can be maintained statically in specialized subclasses of Parser. |
|
Parser(Bindings bindings,
java.util.Map<java.lang.String,Entity> entities)
creates a new Parser with bindings and entities that can be maintained statically in specialized subclasses of Parser. |
Method Summary | |
---|---|
void |
addEntity(java.lang.String publicId,
Entity entity)
adds a resolver to the schema catalog. |
protected org.w3c.dom.Document |
buildDom(Parse parse)
customizable DOM building. |
void |
checkProblems(java.lang.String description,
Parse parse)
throws an exception with appropriate message in case the parse contains errors or fatal errors. |
protected javax.xml.parsers.DocumentBuilder |
createDocumentBuilder(Parse parse)
customizable creation of a new document builder. |
Parse |
createParse()
main method to start a new parse, check Parse for specifying
input, executing the parse and extracting the results. |
protected void |
execute(Parse parse)
customizable parse execution |
Binding |
getBinding(org.w3c.dom.Element element)
the handler for the given element |
Binding |
getBinding(org.w3c.dom.Element element,
java.lang.String category)
the handler for the given element limited to a given category |
Bindings |
getBindings()
the handlers for specific element types |
javax.xml.parsers.DocumentBuilderFactory |
getDocumentBuilderFactory()
getter with lazy initialization of the document builder factory. |
protected org.xml.sax.InputSource |
getInputSource(Parse parse)
customizable extraction of the inputSource from the given parse. |
void |
importStream(StreamSource importedStreamSource,
org.w3c.dom.Element destination,
Parse importingParse)
builds a dom from the importedStreamSource and appends the child elements of the document element to the destination element. |
protected javax.xml.parsers.DocumentBuilderFactory |
newDocumentBuilderFactory()
factory method for DocumentBuilderFactory during lazy initialization
of the documentBuilderFactory. |
java.lang.Object |
parseDocument(org.w3c.dom.Document document,
Parse parse)
start of the DOM walk. |
java.lang.Object |
parseDocumentElement(org.w3c.dom.Element documentElement,
Parse parse)
parses the top level element in the document and produces the object that is the result from the parsing. |
java.lang.Object |
parseElement(org.w3c.dom.Element element,
Parse parse)
parses an arbitrary element in the document with the first matching binding found using any of the categories. |
java.lang.Object |
parseElement(org.w3c.dom.Element element,
Parse parse,
java.lang.String category)
parses an arbitrary element in the document based on the bindings in the given category. |
org.xml.sax.InputSource |
resolveEntity(java.lang.String publicId,
java.lang.String systemId)
implementation of EntityResolver based on a map of Entity s. |
void |
setBindings(Bindings bindings)
set the handlers for specific element types |
void |
setDocumentBuilderFactory(javax.xml.parsers.DocumentBuilderFactory documentBuilderFactory)
setter for the document builder factory |
void |
useParseEntityResolver()
makes sure that an EntityResolver is created based on the Entity s in this parser. |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
protected javax.xml.parsers.DocumentBuilderFactory documentBuilderFactory
protected java.util.Map<java.lang.String,Entity> entities
protected Bindings bindings
protected java.lang.ClassLoader classLoader
Constructor Detail |
---|
public Parser()
public Parser(Bindings bindings)
public Parser(Bindings bindings, java.util.Map<java.lang.String,Entity> entities)
Method Detail |
---|
public javax.xml.parsers.DocumentBuilderFactory getDocumentBuilderFactory()
setDocumentBuilderFactory(DocumentBuilderFactory)
method, newDocumentBuilderFactory()
will be called to create one.
public void setDocumentBuilderFactory(javax.xml.parsers.DocumentBuilderFactory documentBuilderFactory)
protected javax.xml.parsers.DocumentBuilderFactory newDocumentBuilderFactory()
DocumentBuilderFactory
during lazy initialization
of the documentBuilderFactory. Can be overridden by subclasses to change
the DocumentBuilderFactory implementation or to apply specific configurations.
public void addEntity(java.lang.String publicId, Entity entity)
public void useParseEntityResolver()
EntityResolver
is created based on the Entity
s in this parser.
even when none of the addEntity(String, Entity)
methods are called.
This enables addition of entities on a per-Parse
basis when there are no parser-level entities.
public org.xml.sax.InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId)
EntityResolver
based on a map of Entity
s.
See also section 'Entity resolving'.
resolveEntity
in interface org.xml.sax.EntityResolver
addEntity(String, Entity)
public Bindings getBindings()
public void setBindings(Bindings bindings)
public Binding getBinding(org.w3c.dom.Element element)
public Binding getBinding(org.w3c.dom.Element element, java.lang.String category)
public Parse createParse()
Parse
for specifying
input, executing the parse and extracting the results.
public void importStream(StreamSource importedStreamSource, org.w3c.dom.Element destination, Parse importingParse)
protected void execute(Parse parse)
protected org.w3c.dom.Document buildDom(Parse parse)
the
input specified in the parse
with a
DocumentBuilder
.
protected javax.xml.parsers.DocumentBuilder createDocumentBuilder(Parse parse)
buildDom(Parse)
.
protected org.xml.sax.InputSource getInputSource(Parse parse)
execute(Parse)
.
public java.lang.Object parseDocument(org.w3c.dom.Document document, Parse parse)
the parse execution
.
This default implementation behaviour extracts the document element and
delegates to parseDocumentElement(Element, Parse)
.
This method can be overridden for customized behaviour.
public java.lang.Object parseDocumentElement(org.w3c.dom.Element documentElement, Parse parse)
public java.lang.Object parseElement(org.w3c.dom.Element element, Parse parse)
public java.lang.Object parseElement(org.w3c.dom.Element element, Parse parse, java.lang.String category)
category
- is the category in which the tagName should be resolved to
a Binding
. If category is null, all the categories will be
scanned for an appropriate binding in random order.
public void checkProblems(java.lang.String description, Parse parse)
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |