
uk.gov.nationalarchives.droid.xmlReader.SAXModelBuilder Maven / Gradle / Ivy
Show all versions of wazformat Show documentation
/*
* c The National Archives 2005-2006. All rights reserved.
* See Licence.txt for full licence details.
*
* Developed by:
* Tessella Support Services plc
* 3 Vineyard Chambers
* Abingdon, OX14 3PX
* United Kingdom
* http://www.tessella.com
*
* Tessella/NPD/4305
* PRONOM 4
*
* SAXModelBuilder.java
*
* $Id: SAXModelBuilder.java,v 1.7 2006/03/13 15:15:29 linb Exp $
*
* $Logger: SAXModelBuilder.java,v $
* Revision 1.7 2006/03/13 15:15:29 linb
* Changed copyright holder from Crown Copyright to The National Archives.
* Added reference to licence.txt
* Changed dates to 2005-2006
*
* Revision 1.6 2006/02/09 15:31:23 linb
* Updates to javadoc and code following the code review
*
* Revision 1.5 2006/01/31 16:47:30 linb
* Added log messages that were missing due to the log keyword being added too late
*
* Revision 1.4 2006/01/31 16:21:20 linb
* Removed the dollars from the log lines generated by the previous message, so as not to cause problems with subsequent commits
*
* Revision 1.3 2006/01/31 16:19:07 linb
* Added Logger and Id tags to these files
*
* Revision 1.2 2006/01/31 16:11:37 linb
* Add support for XML namespaces to:
* 1) The reading of the config file, spec file and file-list file
* 2) The writing of the config file and file-list file
* - The namespaces still need to be set to their proper URIs (currently set to example.com...)
* - Can still read in files without namespaces*
*
*/
package uk.gov.nationalarchives.droid.xmlReader;
import java.lang.reflect.Method;
import java.util.Stack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import uk.gov.nationalarchives.droid.base.SimpleElement;
/**
* reads and parses data from an XML file
*
* @version 4.0.0
*/
public class SAXModelBuilder extends DefaultHandler {
private Stack stack = new Stack();
private SimpleElement element;
private String myObjectPackage = "uk.gov.nationalarchives.droid.signatureFile";
StringBuffer textBuffer;
private String namespace = "";
private boolean useNamespace = false;
private boolean allowGlobalNamespace = true;
private static final Logger LOG = LoggerFactory
.getLogger(SAXModelBuilder.class);
@Override
public void characters(final char[] ch, final int start, final int len) {
if (!this.stack.empty()) { // Ignore character data if we don't have an
// element to put it in.
final String text = new String(ch, start, len);
(this.stack.peek()).setText(text);
}
}
@Override
public void endElement(final String namespace, final String localname,
final String qname) throws SAXException {
final String elementName = handleNameNS(namespace, localname, qname);
if (elementName == null) {
return;
}
this.element = this.stack.pop();
this.element.completeElementContent();
if (!this.stack.empty()) {
try {
setProperty(elementName, this.stack.peek(), this.element);
} catch (final SAXException e) {
throw new SAXException(e);
}
}
}
public SimpleElement getModel() {
return this.element;
}
public void setObjectPackage(final String theObjectPackage) {
this.myObjectPackage = theObjectPackage;
}
/**
* Set up XML namespace handling.
*
*
* If allowGlobalNamespace
is set to true
,
* elements that do not have a namespace specified are parsed; attributes
* that don't have a namespace specified are parsed. If it is
* false
, for it to be parsed, an element must have a namespace
* specifed (by default or with a prefix); an attribute must have a
* namespace specified with a prefix.
*
* @param namespace
* the XML namespace to use
* @param allowGlobalNamespace
* allow the parser to recognise elements/ attributes that aren't
* in any namespace
*/
public void setupNamespace(final String namespace,
final boolean allowGlobalNamespace) {
if (namespace == null) {
throw new IllegalArgumentException("Namespace cannot be null");
}
this.namespace = namespace;
this.useNamespace = true;
this.allowGlobalNamespace = allowGlobalNamespace;
}
@Override
public void startElement(final String namespace, final String localname,
final String qname, final Attributes atts) throws SAXException {
final String elementName = handleNameNS(namespace, localname, qname);
if (elementName == null) {
return;
}
SimpleElement element = null;
final String className = this.myObjectPackage + "." + elementName;
try {
element = (SimpleElement) Class.forName(className).newInstance();
} catch (final Exception e) {
}
if (element == null) {
element = new SimpleElement();
}
for (int i = 0; i < atts.getLength(); i++) {
final String attributeName = handleNameNS(atts.getURI(i), atts
.getLocalName(i), atts.getQName(i));
if (attributeName == null) {
continue;
}
element.setAttributeValue(attributeName, atts.getValue(i));
}
this.stack.push(element);
}
/**
* Handle names in a namespace-aware fashion.
*
*
* If an element/ attribute is in a namespace, qname is not required to be
* set. We must, therefore, use the localname if the namespace is set, and
* qname if it isn't.
*
* @param namespace
* the namespace uri
* @param localname
* the local part of the name
* @param qname
* a qualified name
* @return the local part or the qualified name, as appropriate
*/
private String handleNameNS(final String namespace,
final String localname, final String qname) {
if (this.useNamespace && this.namespace.equals(namespace)) {
// Name is in the specified namespace
return localname;
} else if (this.allowGlobalNamespace && "".equals(namespace)) {
// Name is in the global namespace
return qname;
} else {
// Ignore
return null;
}
}
void setProperty(final String name, final Object target, Object value)
throws SAXException {
Method method = null;
try {
method = target.getClass().getMethod("add" + name,
new Class[] { value.getClass() });
} catch (final NoSuchMethodException e) {
}
if (method == null) {
try {
method = target.getClass().getMethod("set" + name,
new Class[] { value.getClass() });
} catch (final NoSuchMethodException e) {
}
}
if (method == null) {
try {
value = ((SimpleElement) value).getText();
method = target.getClass().getMethod("add" + name,
new Class[] { String.class });
} catch (final NoSuchMethodException e) {
}
}
try {
if (method == null) {
method = target.getClass().getMethod("set" + name,
new Class[] { String.class });
}
method.invoke(target, value);
} catch (final NoSuchMethodException e) {
LOG.error("unknown element {} {}",name, ((SimpleElement) target)
.getElementName());
} catch (final Exception e) {
throw new SAXException(e);
}
}
}