in core/camel-xml-io/src/main/java/org/apache/camel/xml/io/MXParser.java [1849:2098]
protected char parseAttribute() throws XmlPullParserException, IOException {
// parse attribute
// [41] Attribute ::= Name Eq AttValue
// [WFC: No External Entity References]
// [WFC: No < in Attribute Values]
final int prevPosStart = posStart + bufAbsoluteStart;
final int nameStart = pos - 1 + bufAbsoluteStart;
int colonPos = -1;
char ch = buf[pos - 1];
if (ch == ':' && processNamespaces)
throw new XmlPullParserException(
"when namespaces processing enabled colon can not be at attribute name start", this, null);
boolean startsWithXmlns = processNamespaces && ch == 'x';
int xmlnsPos = 0;
ch = more();
while (isNameChar(ch)) {
if (processNamespaces) {
if (startsWithXmlns && xmlnsPos < 5) {
++xmlnsPos;
if (xmlnsPos == 1) {
if (ch != 'm')
startsWithXmlns = false;
} else if (xmlnsPos == 2) {
if (ch != 'l')
startsWithXmlns = false;
} else if (xmlnsPos == 3) {
if (ch != 'n')
startsWithXmlns = false;
} else if (xmlnsPos == 4) {
if (ch != 's')
startsWithXmlns = false;
} else {
if (ch != ':')
throw new XmlPullParserException(
"after xmlns in attribute name must be colon" + " when namespaces are enabled", this, null);
// colonPos = pos - 1 + bufAbsoluteStart;
}
}
if (ch == ':') {
if (colonPos != -1)
throw new XmlPullParserException(
"only one colon is allowed in attribute name" + " when namespaces are enabled", this, null);
colonPos = pos - 1 + bufAbsoluteStart;
}
}
ch = more();
}
ensureAttributesCapacity(attributeCount);
// --- start processing attributes
String name = null;
String prefix = null;
// work on prefixes and namespace URI
if (processNamespaces) {
if (xmlnsPos < 4)
startsWithXmlns = false;
if (startsWithXmlns) {
if (colonPos != -1) {
// prefix = attributePrefix[ attributeCount ] = null;
final int nameLen = pos - 2 - (colonPos - bufAbsoluteStart);
if (nameLen == 0) {
throw new XmlPullParserException(
"namespace prefix is required after xmlns: " + " when namespaces are enabled", this, null);
}
name = // attributeName[ attributeCount ] =
newString(buf, colonPos - bufAbsoluteStart + 1, nameLen);
// pos - 1 - (colonPos + 1 - bufAbsoluteStart)
}
} else {
if (colonPos != -1) {
int prefixLen = colonPos - nameStart;
prefix = attributePrefix[attributeCount] = newString(buf, nameStart - bufAbsoluteStart, prefixLen);
// colonPos - (nameStart - bufAbsoluteStart));
int nameLen = pos - 2 - (colonPos - bufAbsoluteStart);
name = attributeName[attributeCount] = newString(buf, colonPos - bufAbsoluteStart + 1, nameLen);
// pos - 1 - (colonPos + 1 - bufAbsoluteStart));
// name.substring(0, colonPos-nameStart);
} else {
prefix = attributePrefix[attributeCount] = null;
name = attributeName[attributeCount]
= newString(buf, nameStart - bufAbsoluteStart, pos - 1 - (nameStart - bufAbsoluteStart));
}
if (!allStringsInterned) {
attributeNameHash[attributeCount] = name.hashCode();
}
}
} else {
// retrieve name
name = attributeName[attributeCount]
= newString(buf, nameStart - bufAbsoluteStart, pos - 1 - (nameStart - bufAbsoluteStart));
//// assert name != null;
if (!allStringsInterned) {
attributeNameHash[attributeCount] = name.hashCode();
}
}
// [25] Eq ::= S? '=' S?
while (isS(ch)) {
ch = more();
} // skip additional spaces
if (ch != '=')
throw new XmlPullParserException("expected = after attribute name", this, null);
ch = more();
while (isS(ch)) {
ch = more();
} // skip additional spaces
// [10] AttValue ::= '"' ([^<&"] | Reference)* '"'
// | "'" ([^<&'] | Reference)* "'"
final char delimit = ch;
if (delimit != '"' && delimit != '\'')
throw new XmlPullParserException(
"attribute value must start with quotation or apostrophe not " + printable(delimit), this, null);
// parse until delimit or < and resolve Reference
// [67] Reference ::= EntityRef | CharRef
// int valueStart = pos + bufAbsoluteStart;
boolean normalizedCR = false;
usePC = false;
pcStart = pcEnd;
posStart = pos;
while (true) {
ch = more();
if (ch == delimit) {
break;
}
if (ch == '<') {
throw new XmlPullParserException("markup not allowed inside attribute value - illegal < ", this, null);
}
if (ch == '&') {
// extractEntityRef
posEnd = pos - 1;
if (!usePC) {
final boolean hadCharData = posEnd > posStart;
if (hadCharData) {
// posEnd is already set correctly!!!
joinPC();
} else {
usePC = true;
pcStart = pcEnd = 0;
}
}
// assert usePC == true;
final char[] resolvedEntity = parseEntityRef();
// check if replacement text can be resolved !!!
if (resolvedEntity == null) {
if (entityRefName == null) {
entityRefName = newString(buf, posStart, posEnd - posStart);
}
throw new XmlPullParserException(
"could not resolve entity named '" + printable(entityRefName) + "'", this, null);
}
// write into PC replacement text - do merge for replacement
// text!!!!
for (int i = 0; i < resolvedEntity.length; i++) {
if (pcEnd >= pc.length)
ensurePC(pcEnd);
pc[pcEnd++] = resolvedEntity[i];
}
} else if (ch == '\t' || ch == '\n' || ch == '\r') {
// do attribute value normalization
// as described in http://www.w3.org/TR/REC-xml#AVNormalize
// TODO add test for it form spec ...
// handle EOL normalization ...
if (!usePC) {
posEnd = pos - 1;
if (posEnd > posStart) {
joinPC();
} else {
usePC = true;
pcEnd = pcStart = 0;
}
}
// assert usePC == true;
if (pcEnd >= pc.length)
ensurePC(pcEnd);
if (ch != '\n' || !normalizedCR) {
pc[pcEnd++] = ' '; // '\n';
}
} else {
if (usePC) {
if (pcEnd >= pc.length)
ensurePC(pcEnd);
pc[pcEnd++] = ch;
}
}
normalizedCR = ch == '\r';
}
if (processNamespaces && startsWithXmlns) {
String ns;
if (!usePC) {
ns = newStringIntern(buf, posStart, pos - 1 - posStart);
} else {
ns = newStringIntern(pc, pcStart, pcEnd - pcStart);
}
ensureNamespacesCapacity(namespaceEnd);
int prefixHash = -1;
if (colonPos != -1) {
if (ns.isEmpty()) {
throw new XmlPullParserException(
"non-default namespace can not be declared to be empty string", this, null);
}
// declare new namespace
namespacePrefix[namespaceEnd] = name;
if (!allStringsInterned) {
prefixHash = namespacePrefixHash[namespaceEnd] = name.hashCode();
}
} else {
// declare new default namespace ...
namespacePrefix[namespaceEnd] = null; // ""; //null; //TODO
// check FIXME Alek
if (!allStringsInterned) {
prefixHash = namespacePrefixHash[namespaceEnd] = -1;
}
}
namespaceUri[namespaceEnd] = ns;
// detect duplicate namespace declarations!!!
final int startNs = elNamespaceCount[depth - 1];
for (int i = namespaceEnd - 1; i >= startNs; --i) {
if (((allStringsInterned || name == null) && namespacePrefix[i] == name)
|| (!allStringsInterned && name != null && namespacePrefixHash[i] == prefixHash
&& name.equals(namespacePrefix[i]))) {
final String s = name == null ? "default" : "'" + name + "'";
throw new XmlPullParserException("duplicated namespace declaration for " + s + " prefix", this, null);
}
}
++namespaceEnd;
} else {
if (!usePC) {
attributeValue[attributeCount] = new String(buf, posStart, pos - 1 - posStart);
} else {
attributeValue[attributeCount] = new String(pc, pcStart, pcEnd - pcStart);
}
++attributeCount;
}
posStart = prevPosStart - bufAbsoluteStart;
return ch;
}