de.odysseus.staxon.base.AbstractXMLStreamScope Maven / Gradle / Ivy
/*
* Copyright 2011 Odysseus Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.odysseus.staxon.base;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.XMLStreamException;
/**
* Represent document/element scope. Used to store namespace bindings and
* attributes, implements {@link NamespaceContext}.
*/
public abstract class AbstractXMLStreamScope implements NamespaceContext {
class Attr {
private final String prefix;
private final String localName;
private final String namespaceURI;
private final String value;
Attr(String prefix, String localName, String namespaceURI, String value) {
this.prefix = prefix;
this.localName = localName;
this.namespaceURI = namespaceURI;
this.value = value;
}
String getPrefix() {
if (prefix != null) {
return prefix;
} else if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
return XMLConstants.DEFAULT_NS_PREFIX;
} else {
return AbstractXMLStreamScope.this.getNonEmptyPrefix(namespaceURI);
}
}
String getLocalName() {
return localName;
}
String getNamespaceURI() {
if (namespaceURI != null) {
return namespaceURI;
} else if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
return XMLConstants.NULL_NS_URI;
} else {
return AbstractXMLStreamScope.this.getNamespaceURI(prefix);
}
}
String getValue() {
return value;
}
void verify() throws XMLStreamException {
if (prefix == null) {
if (!XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
String prefix = AbstractXMLStreamScope.this.getNonEmptyPrefix(namespaceURI);
if (prefix == null) {
throw new XMLStreamException("No prefix found for attribute namespace: " + namespaceURI);
}
}
} else if (namespaceURI == null) {
if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
String namespaceURI = AbstractXMLStreamScope.this.getNamespaceURI(prefix);
if (namespaceURI == null || XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
throw new XMLStreamException("Unbound attribute prefix: " + prefix);
}
}
} else {
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
if (!XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
throw new XMLStreamException("Illegal namespace for unprefixed attribute: " + namespaceURI);
}
} else if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
throw new XMLStreamException("Illegal prefix for null namespace: " + prefix);
}
} else {
if (!AbstractXMLStreamScope.this.getNamespaceURI(prefix).equals(namespaceURI)) {
throw new XMLStreamException("Prefix '" + prefix +"' is not bound to: " + namespaceURI);
}
}
}
}
}
private final NamespaceContext parent;
private final String prefix;
private final String localName;
private final String namespaceURI;
private String defaultNamespace;
private List attributes;
private List> prefixes;
private AbstractXMLStreamScope lastChild;
private boolean startTagClosed;
/**
* Create root scope.
*
* @param defaultNamespace
*/
public AbstractXMLStreamScope(String defaultNamespace) {
this.parent = null;
this.prefix = null;
this.localName = null;
this.namespaceURI = XMLConstants.NULL_NS_URI;
this.defaultNamespace = defaultNamespace;
this.startTagClosed = true;
}
/**
* Create root scope.
*
* @param parent
* root namespace context
*/
public AbstractXMLStreamScope(NamespaceContext parent) {
this.parent = parent;
this.prefix = null;
this.localName = null;
this.namespaceURI = XMLConstants.NULL_NS_URI;
this.defaultNamespace = parent.getNamespaceURI(XMLConstants.NULL_NS_URI);
this.startTagClosed = true;
}
/**
* Create element scope.
*
* @param parent
* @param prefix
* @param localName
*/
public AbstractXMLStreamScope(AbstractXMLStreamScope parent, String prefix, String localName, String namespaceURI) {
this.parent = parent;
this.prefix = prefix;
this.localName = localName;
this.namespaceURI = namespaceURI;
this.startTagClosed = false;
this.defaultNamespace = parent.getNamespaceURI(XMLConstants.NULL_NS_URI);
parent.lastChild = this;
parent.startTagClosed = true;
}
void addAttribute(String prefix, String localName, String namespaceURI, String value) {
if (attributes == null) {
attributes = new LinkedList();
}
attributes.add(new Attr(prefix, localName, namespaceURI, value));
}
List getAttributes() {
return attributes;
}
public String getPrefix() {
return prefix == null ? getPrefix(namespaceURI) : prefix;
}
public String getLocalName() {
return localName;
}
public String getNamespaceURI() {
return namespaceURI == null ? getNamespaceURI(prefix) : namespaceURI;
}
public boolean isRoot() {
return localName == null;
}
public AbstractXMLStreamScope getParent() {
return isRoot() ? null : (AbstractXMLStreamScope)parent;
}
public AbstractXMLStreamScope getLastChild() {
return lastChild;
}
public boolean isStartTagClosed() {
return startTagClosed;
}
private void verify() throws XMLStreamException {
if (prefix == null) {
if (!XMLConstants.NULL_NS_URI.equals(namespaceURI) && getPrefix(namespaceURI) == null) {
throw new XMLStreamException("No prefix for namespace URI: " + namespaceURI);
}
} else if (namespaceURI == null) {
if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix) && XMLConstants.NULL_NS_URI.equals(getNamespaceURI(prefix))) {
throw new XMLStreamException("Unbound prefix: " + prefix);
}
} else {
if (!namespaceURI.equals(getNamespaceURI(prefix))) {
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
throw new XMLStreamException("Prefix required for namespace URI: '" + namespaceURI);
} else if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
throw new XMLStreamException("Prefix '" + prefix +"' is bound to: " + getNamespaceURI(prefix));
} else {
throw new XMLStreamException("Prefix '" + prefix +"' is not bound to: " + namespaceURI);
}
}
}
if (attributes != null) {
for (Attr attribute : attributes) {
attribute.verify();
}
}
}
void setStartTagClosed(boolean startTagClosed) throws XMLStreamException {
if (startTagClosed) {
verify();
}
this.startTagClosed = startTagClosed;
}
private String findNonEmptyPrefix(String namespaceURI, AbstractXMLStreamScope descendent) {
if (prefixes != null) {
for (Pair pair : prefixes) {
if (pair.getSecond().equals(namespaceURI)) {
if (descendent == this || descendent.getNamespaceURI(pair.getFirst()).equals(namespaceURI)) {
return pair.getFirst();
}
}
}
}
if (isRoot()) {
if (parent == null) {
return null;
} else {
Iterator> prefixes = parent.getPrefixes(namespaceURI);
while (prefixes.hasNext()) {
String prefix = prefixes.next().toString();
if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
if (descendent == this || descendent.getNamespaceURI(prefix).equals(namespaceURI)) {
return prefix;
}
}
}
return null;
}
} else {
return getParent().findNonEmptyPrefix(namespaceURI, descendent);
}
}
String getNonEmptyPrefix(String namespaceURI) {
if (namespaceURI == null) {
throw new IllegalArgumentException("Namespace URI must not be null");
} else if (XMLConstants.XML_NS_URI.equals(namespaceURI)) {
return XMLConstants.XML_NS_PREFIX;
} else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) {
return XMLConstants.XMLNS_ATTRIBUTE;
} else {
return findNonEmptyPrefix(namespaceURI, this);
}
}
@Override
public String getPrefix(String namespaceURI) {
if (XMLConstants.NULL_NS_URI.equals(namespaceURI)) {
return null;
} else if (defaultNamespace.equals(namespaceURI)) {
return XMLConstants.DEFAULT_NS_PREFIX;
} else {
return getNonEmptyPrefix(namespaceURI);
}
}
public void setPrefix(String prefix, String namespaceURI) {
if (prefix == null || namespaceURI == null) {
throw new IllegalArgumentException("Prefix and namespace URI must not be null");
}
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
defaultNamespace = namespaceURI;
} else if (XMLConstants.XML_NS_PREFIX.equals(namespaceURI)) {
throw new IllegalArgumentException("Cannot bind to prefix: " + prefix);
} else if (XMLConstants.XMLNS_ATTRIBUTE.equals(namespaceURI)) {
throw new IllegalArgumentException("Cannot bind to prefix: " + prefix);
} else {
if (prefixes == null) {
prefixes = new LinkedList>();
} else {
Iterator> iterator = prefixes.iterator();
while (iterator.hasNext()) {
if (iterator.next().getFirst().equals(prefix)) {
iterator.remove();
}
}
}
prefixes.add(new Pair(prefix, namespaceURI));
}
}
@Override
public Iterator getPrefixes(final String namespaceURI) {
if (namespaceURI == null) {
throw new IllegalArgumentException("Namespace URI must not be null");
} else if (XMLConstants.XML_NS_URI.equals(namespaceURI)) {
return Arrays.asList(XMLConstants.XML_NS_PREFIX).iterator();
} else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) {
return Arrays.asList(XMLConstants.XMLNS_ATTRIBUTE).iterator();
} else {
return new Iterator() {
int state = 0;
String next = null;
Iterator> pairs;
Iterator> above;
private String next0() {
if (state == 0) { // check default
state = 1;
if (namespaceURI.equals(defaultNamespace)) {
return XMLConstants.DEFAULT_NS_PREFIX;
}
}
if (state == 1) { // check pairs
if (prefixes != null) {
if (pairs == null) {
pairs = prefixes.iterator();
}
while (pairs.hasNext()) {
Pair pair = pairs.next();
if (namespaceURI.equals(pair.getSecond())) {
return pair.getFirst();
}
}
}
state = 2;
}
if (state == 2) { // check above
if (parent != null) {
if (above == null) {
above = parent.getPrefixes(namespaceURI);
}
while (above.hasNext()) {
String prefix = above.next().toString();
if (getNamespaceURI(prefix).equals(namespaceURI)) {
return prefix;
}
}
}
state = 3;
}
if (state == 3) { // check out...
return null;
}
throw new IllegalStateException(); // should not happen
}
@Override
public boolean hasNext() {
if (next == null) {
next = next0();
}
return next != null;
}
@Override
public String next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
String result = next;
next = null;
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove prefix");
}
};
}
}
@Override
public String getNamespaceURI(String prefix) {
if (prefix == null) {
throw new IllegalArgumentException("Prefix must not be null");
} else if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
return defaultNamespace;
} else if (XMLConstants.XML_NS_PREFIX.equals(prefix)) {
return XMLConstants.XML_NS_URI;
} else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
} else {
if (prefixes != null) {
for (Pair pair : prefixes) {
if (pair.getFirst().equals(prefix)) {
return pair.getSecond();
}
}
}
return parent == null ? XMLConstants.NULL_NS_URI : parent.getNamespaceURI(prefix);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy