Skip to Content.
Sympa Menu

xom-interest - Re: [XOM-interest] Consider adding Builder.getXMLReader()

xom-interest AT lists.ibiblio.org

Subject: XOM API for Processing XML with Java

List archive

Chronological Thread  
  • From: Wolfgang Hoschek <whoschek AT lbl.gov>
  • To: Elliotte Rusty Harold <elharo AT metalab.unc.edu>
  • Cc: xom-interest AT lists.ibiblio.org
  • Subject: Re: [XOM-interest] Consider adding Builder.getXMLReader()
  • Date: Fri, 10 Oct 2003 12:47:49 -0700

I thought about the issue some more, and came up with a better solution for proposal: Add a constructor to builder that specifies which SAX properties and features the underlying XMLReader should at least have.

This eliminates code duplication and fragility and makes it very easy to use. For example if you'd wanted a builder that validates against a W3C XML Schema (optionally external), one would write along the following lines:

Map propsAndFeatures = new HashMap();
propsAndFeatures.put("http://apache.org/xml/features/validation/schema";, new Boolean(true));
if (namespace != null && schema != null) {
propsAndFeatures.put( "http://apache.org/xml/properties/schema/external-schemaLocation";,
namespace + " " + schema);
}
else if (schema != null) {
propsAndFeatures.put( "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";,
schema);
}
Builder builder = new Builder(validate, null, propsAndFeatures);


Here are the code changes to Builder (xom-1.0d21) that add said functionality, without breaking any existing apps (also attached as a file):

import java.util.Map;
...

public Builder(boolean validate) {
this(validate, null);
//this(findParser(validate), validate, null);
}

public Builder(boolean validate, NodeFactory factory) {
this(validate, factory, null);
//this(findParser(validate), validate, factory);
}

public Builder(boolean validate, NodeFactory factory, Map propertiesAndFeatures) {
this(findParser(validate, propertiesAndFeatures), validate,
factory);
}

public Builder(XMLReader parser, boolean validate, NodeFactory factory) {
try {
setupParser(parser, validate, null);
//setupParser(parser, validate);
}
...
}

private static XMLReader findParser(boolean validate, Map propertiesAndFeatures) {

// XMLReaderFactory.createXMLReader never returns
// null. If it can't locate the parser, it throws
// a SAXException.
XMLReader parser = null;
for (int i = 0; i < parsers.length; i++) {
try {
parser =
XMLReaderFactory.createXMLReader(parsers[i]);
setupParser(parser, validate,
propertiesAndFeatures); // WH changed
//setupParser(parser, validate);
return parser;
}
catch (SAXException ex) {
parser = null;
// try the next one
}
}

if (parser == null) {
try { // default
parser = XMLReaderFactory.createXMLReader();
setupParser(parser, validate,
propertiesAndFeatures); // WH changed
//setupParser(parser, validate);
}
catch (SAXException ex) {
throw new XMLException(
"Could not find a suitable SAX2 parser",
ex);
}
}

return parser;

}


private static void setupParser(XMLReader parser, boolean validate, Map propertiesAndFeatures)
throws SAXNotRecognizedException, SAXNotSupportedException {

if (!validate) {
...
}
else {
...
}

try {
parser.setFeature(
"http://xml.org/sax/features/string-interning";,
true);
}
catch (SAXException ex) {
// This parser does not support string interning.
// We can live without that.
}

// WH added:
if (propertiesAndFeatures != null) {
Iterator iter =
propertiesAndFeatures.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String key = entry.getKey().toString();
Object value = entry.getValue();
if (value instanceof Boolean) {
parser.setFeature(key, ((Boolean)
value).booleanValue());
}
else {
parser.setProperty(key, value);
}
}
}
}




Elliotte Rusty Harold wrote:
At 10:27 AM -0700 10/3/03, Wolfgang Hoschek wrote:

I still need to find a parser myself and hence duplicate the good and solid code within Builder (findParsers(), setupParser()), that normally takes care of this fragile step. This would be quite a bit easier if Builder had a method

public XMLReader getXMLReader() {
return this.parser;
}

(or perhaps better named getParser()) so that I could get hold of the reader and then customize it afterwards, ala:

builder = new Builder(true);
builder.getXMLReader().setFeature(...);
builder.build(...)


The problem with that is there's no guarantee which parser you'll get. If you're going to use custom SAX features and properties such as http://apache.org/xml/features/validation/schema then I assume you're going to want to provide a parser that is known to support those features and properties.

import java.util.Map;
...

public Builder(boolean validate) {
this(validate, null);
//this(findParser(validate), validate, null);
}

public Builder(boolean validate, NodeFactory factory) {
this(validate, factory, null);
//this(findParser(validate), validate, factory);
}

public Builder(boolean validate, NodeFactory factory, Map
propertiesAndFeatures) {
this(findParser(validate, propertiesAndFeatures), validate,
factory);
}

public Builder(XMLReader parser, boolean validate, NodeFactory factory) {

try {
setupParser(parser, validate, null);
//setupParser(parser, validate);
}
...
}

private static XMLReader findParser(boolean validate, Map
propertiesAndFeatures) {

// XMLReaderFactory.createXMLReader never returns
// null. If it can't locate the parser, it throws
// a SAXException.
XMLReader parser = null;
for (int i = 0; i < parsers.length; i++) {
try {
parser =
XMLReaderFactory.createXMLReader(parsers[i]);
setupParser(parser, validate,
propertiesAndFeatures); // WH changed
//setupParser(parser, validate);
return parser;
}
catch (SAXException ex) {
parser = null;
// try the next one
}
}

if (parser == null) {
try { // default
parser = XMLReaderFactory.createXMLReader();
setupParser(parser, validate,
propertiesAndFeatures); // WH changed
//setupParser(parser, validate);
}
catch (SAXException ex) {
throw new XMLException(
"Could not find a suitable SAX2 parser",
ex);
}
}

return parser;

}


private static void setupParser(XMLReader parser, boolean validate,
Map propertiesAndFeatures)
throws SAXNotRecognizedException, SAXNotSupportedException {

if (!validate) {
...
}
else {
...
}

try {
parser.setFeature(
"http://xml.org/sax/features/string-interning";,
true);
}
catch (SAXException ex) {
// This parser does not support string interning.
// We can live without that.
}

// WH added:
if (propertiesAndFeatures != null) {
Iterator iter =
propertiesAndFeatures.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String key = entry.getKey().toString();
Object value = entry.getValue();
if (value instanceof Boolean) {
parser.setFeature(key, ((Boolean)
value).booleanValue());
}
else {
parser.setProperty(key, value);
}
}
}
}



Archive powered by MHonArc 2.6.24.

Top of Page