package com.ctc.wstx.dtd;
import javax.xml.stream.XMLStreamException;
import com.ctc.wstx.io.WstxInputData;
import com.ctc.wstx.sr.InputProblemReporter;
import com.ctc.wstx.util.PrefixedName;
Specific attribute class for attributes that contain (unique)
identifiers.
/**
* Specific attribute class for attributes that contain (unique)
* identifiers.
*/
public final class DTDNmTokensAttr
extends DTDAttribute
{
/*
///////////////////////////////////////////////////
// Life-cycle
///////////////////////////////////////////////////
*/
Main constructor.
/**
* Main constructor.
*/
public DTDNmTokensAttr(PrefixedName name, DefaultAttrValue defValue, int specIndex,
boolean nsAware, boolean xml11)
{
super(name, defValue, specIndex, nsAware, xml11);
}
@Override
public DTDAttribute cloneWith(int specIndex) {
return new DTDNmTokensAttr(mName, mDefValue, specIndex, mCfgNsAware, mCfgXml11);
}
/*
///////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////
*/
@Override
public int getValueType() {
return TYPE_NMTOKENS;
}
/*
///////////////////////////////////////////////////
// Public API, validation
///////////////////////////////////////////////////
*/
Method called by the validator
to let the attribute do necessary normalization and/or validation
for the value.
/**
* Method called by the validator
* to let the attribute do necessary normalization and/or validation
* for the value.
*/
@Override
public String validate(DTDValidatorBase v, char[] cbuf, int start, int end, boolean normalize)
throws XMLStreamException
{
//int origStart = start;
/* First things first; let's ensure value is not empty (all
* white space)...
*/
while (start < end && WstxInputData.isSpaceChar(cbuf[start])) {
++start;
}
// Empty value?
if (start >= end) {
return reportValidationProblem(v, "Empty NMTOKENS value");
}
/* Then, let's have separate handling for normalizing and
* non-normalizing case, since latter is trivially easy case:
*/
if (!normalize) {
for (; start < end; ++start) {
char c = cbuf[start];
if (!WstxInputData.isSpaceChar(c)
&& !WstxInputData.isNameChar(c, mCfgNsAware, mCfgXml11)) {
return reportInvalidChar(v, c, "not valid as NMTOKENS character");
}
}
return null; // ok, all good
}
//boolean trimmed = (origStart != start);
//origStart = start;
--end; // so that it now points to the last char
// Wouldn't absolutely have to trim trailing... but is easy to do
while (end > start && WstxInputData.isSpaceChar(cbuf[end])) {
--end;
//trimmed = true;
}
/* Ok, now, need to check we only have valid chars, and maybe
* also coalesce multiple spaces, if any.
*/
StringBuilder sb = null;
while (start <= end) {
int i = start;
for (; i <= end; ++i) {
char c = cbuf[i];
if (WstxInputData.isSpaceChar(c)) {
break;
}
if (!WstxInputData.isNameChar(c, mCfgNsAware, mCfgXml11)) {
return reportInvalidChar(v, c, "not valid as an NMTOKENS character");
}
}
if (sb == null) {
sb = new StringBuilder(end - start + 1);
} else {
sb.append(' ');
}
sb.append(cbuf, start, (i - start));
start = i + 1;
// Ok, any white space to skip?
while (start <= end && WstxInputData.isSpaceChar(cbuf[start])) {
++start;
}
}
/* 27-Nov-2005, TSa: Could actually optimize trimming, and often
* avoid using StringBuilder... but let's only do it if it turns
* out dealing with NMTOKENS normalization shows up on profiling...
*/
return sb.toString();
}
Method called by the validator
to ask attribute to verify that the default it has (if any) is
valid for such type.
/**
* Method called by the validator
* to ask attribute to verify that the default it has (if any) is
* valid for such type.
*/
@Override
public void validateDefault(InputProblemReporter rep, boolean normalize)
throws XMLStreamException
{
String defValue = mDefValue.getValue();
int len = defValue.length();
// Then code similar to actual value validation:
StringBuilder sb = null;
int count = 0;
int start = 0;
main_loop:
while (start < len) {
char c = defValue.charAt(start);
// Ok, any white space to skip?
while (true) {
if (!WstxInputData.isSpaceChar(c)) {
break;
}
if (++start >= len) {
break main_loop;
}
c = defValue.charAt(start);
}
int i = start+1;
do {
if (++i >= len) {
break;
}
c = defValue.charAt(i);
} while (!WstxInputData.isSpaceChar(c));
++count;
String token = defValue.substring(start, i);
int illegalIx = WstxInputData.findIllegalNmtokenChar(token, mCfgNsAware, mCfgXml11);
if (illegalIx >= 0) {
reportValidationProblem(rep, "Invalid default value '"+defValue
+"'; character #"+illegalIx+" ("
+WstxInputData.getCharDesc(defValue.charAt(illegalIx))
+") not a valid NMTOKENS character");
}
if (normalize) {
if (sb == null) {
sb = new StringBuilder(i - start + 32);
} else {
sb.append(' ');
}
sb.append(token);
}
start = i+1;
}
if (count == 0) {
reportValidationProblem(rep, "Invalid default value '"+defValue
+"'; empty String is not a valid NMTOKENS value");
return;
}
if (normalize) {
mDefValue.setValue(sb.toString());
}
}
}