org.codehaus.stax2.validation.ValidatorPair Maven / Gradle / Ivy
package org.codehaus.stax2.validation;
import javax.xml.stream.XMLStreamException;
/**
* Simple utility class that allows chaining of {@link XMLValidator}
* instances. Since the class itself implements {@link XMLValidator},
* multiple validators can be added by chaining these pairs; ordering
* of validator calls depends on ordering of the pairs.
*
* Default semantics are quite simple: first validator of the pair is
* always called first, and results as/if modified by that validator
* are passed on to the second validator.
*
* It is expected that this class is mostly used by actual stream reader
* and writer implementations; not so much by validator implementations.
*/
public class ValidatorPair
extends XMLValidator
{
public final static String ATTR_TYPE_DEFAULT = "CDATA";
protected XMLValidator mFirst, mSecond;
/*
////////////////////////////////////////////////////
// Life-cycle
////////////////////////////////////////////////////
*/
public ValidatorPair(XMLValidator first, XMLValidator second)
{
mFirst = first;
mSecond = second;
}
/*
////////////////////////////////////////////////////
// XMLValidator implementation
////////////////////////////////////////////////////
*/
/**
* Two choices here; could either return schema of the first child,
* or return null. Let's do latter, do avoid accidental matches.
*/
@Override
public XMLValidationSchema getSchema() {
return null;
}
@Override
public void validateElementStart(String localName, String uri,
String prefix)
throws XMLStreamException
{
mFirst.validateElementStart(localName, uri, prefix);
mSecond.validateElementStart(localName, uri, prefix);
}
@Override
public String validateAttribute(String localName, String uri,
String prefix, String value)
throws XMLStreamException
{
String retVal = mFirst.validateAttribute(localName, uri, prefix,
value);
if (retVal != null) {
value = retVal;
}
return mSecond.validateAttribute(localName, uri, prefix, value);
}
@Override
public String validateAttribute(String localName, String uri,
String prefix,
char[] valueChars, int valueStart,
int valueEnd)
throws XMLStreamException
{
String retVal = mFirst.validateAttribute(localName, uri, prefix,
valueChars, valueStart, valueEnd);
/* If it got normalized, let's pass normalized value to the second
* validator
*/
if (retVal != null) {
return mSecond.validateAttribute(localName, uri, prefix, retVal);
}
// Otherwise the original
return mSecond.validateAttribute(localName, uri, prefix,
valueChars, valueStart, valueEnd);
}
@Override
public int validateElementAndAttributes()
throws XMLStreamException
{
int textType1 = mFirst.validateElementAndAttributes();
int textType2 = mSecond.validateElementAndAttributes();
/* Here, let's choose the stricter (more restrictive) of the two.
* Since constants are order from strictest to most lenient,
* we'll just take smaller of values
*/
return (textType1 < textType2) ? textType1 : textType2;
}
@Override
public int validateElementEnd(String localName, String uri, String prefix)
throws XMLStreamException
{
int textType1 = mFirst.validateElementEnd(localName, uri, prefix);
int textType2 = mSecond.validateElementEnd(localName, uri, prefix);
// As with earlier, let's return stricter of the two
return (textType1 < textType2) ? textType1 : textType2;
}
@Override
public void validateText(String text, boolean lastTextSegment)
throws XMLStreamException
{
mFirst.validateText(text, lastTextSegment);
mSecond.validateText(text, lastTextSegment);
}
@Override
public void validateText(char[] cbuf, int textStart, int textEnd,
boolean lastTextSegment)
throws XMLStreamException
{
mFirst.validateText(cbuf, textStart, textEnd, lastTextSegment);
mSecond.validateText(cbuf, textStart, textEnd, lastTextSegment);
}
@Override
public void validationCompleted(boolean eod)
throws XMLStreamException
{
mFirst.validationCompleted(eod);
mSecond.validationCompleted(eod);
}
/*
///////////////////////////////////////////////////
// Access to post-validation data (type info)
///////////////////////////////////////////////////
*/
@Override
public String getAttributeType(int index)
{
String type = mFirst.getAttributeType(index);
/* Hmmh. Which heuristic to use here: obviously no answer (null or
* empty) is not useful. But what about the default type (CDATA)?
* We can probably find a more explicit type?
*/
if (type == null || type.length() == 0 || type.equals(ATTR_TYPE_DEFAULT)) {
String type2 = mSecond.getAttributeType(index);
if (type2 != null && type2.length() > 0) {
return type2;
}
}
return type;
}
@Override
public int getIdAttrIndex()
{
int index = mFirst.getIdAttrIndex();
if (index < 0) {
return mSecond.getIdAttrIndex();
}
return index;
}
@Override
public int getNotationAttrIndex()
{
int index = mFirst.getNotationAttrIndex();
if (index < 0) {
return mSecond.getNotationAttrIndex();
}
return index;
}
/*
////////////////////////////////////////////////////
// Additional API used by Woodstox core
////////////////////////////////////////////////////
*/
public static boolean removeValidator(XMLValidator root, XMLValidationSchema schema, XMLValidator[] results)
{
if (root instanceof ValidatorPair) {
return ((ValidatorPair) root).doRemoveValidator(schema, results);
} else {
if (root.getSchema() == schema) {
results[0] = root;
results[1] = null;
return true;
}
}
return false;
}
public static boolean removeValidator(XMLValidator root, XMLValidator vld, XMLValidator[] results)
{
if (root == vld) { // single validator?
results[0] = root;
results[1] = null;
return true;
} else if (root instanceof ValidatorPair) {
return ((ValidatorPair) root).doRemoveValidator(vld, results);
}
return false;
}
private boolean doRemoveValidator(XMLValidationSchema schema, XMLValidator[] results)
{
if (removeValidator(mFirst, schema, results)) {
XMLValidator newFirst = results[1];
if (newFirst == null) { // removed first (was leaf) -> remove this pair
results[1] = mSecond;
} else {
mFirst = newFirst; // two may be the same, need not be
results[1] = this;
}
return true;
}
if (removeValidator(mSecond, schema, results)) {
XMLValidator newSecond = results[1];
if (newSecond == null) { // removed second (was leaf) -> remove this pair
results[1] = mFirst;
} else {
mSecond = newSecond; // two may be the same, need not be
results[1] = this; // will still have this pair
}
return true;
}
return false;
}
private boolean doRemoveValidator(XMLValidator vld, XMLValidator[] results)
{
if (removeValidator(mFirst, vld, results)) {
XMLValidator newFirst = results[1];
if (newFirst == null) { // removed first (was leaf) -> remove this pair
results[1] = mSecond;
} else {
mFirst = newFirst; // two may be the same, need not be
results[1] = this;
}
return true;
}
if (removeValidator(mSecond, vld, results)) {
XMLValidator newSecond = results[1];
if (newSecond == null) { // removed second (was leaf) -> remove this pair
results[1] = mFirst;
} else {
mSecond = newSecond; // two may be the same, need not be
results[1] = this; // will still have this pair
}
return true;
}
return false;
}
/*
////////////////////////////////////////////////////
// Internal methods
////////////////////////////////////////////////////
*/
}