blob: 9abd91c58213b86b01a719c82caaf3ffcc1b841b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.axiom.om.impl.dom;
import org.apache.axiom.om.OMCloneOptions;
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.om.OMXMLParserWrapper;
import org.apache.axiom.om.dom.DOMMetaFactory;
import org.apache.axiom.om.impl.MTOMXMLStreamWriter;
import org.apache.axiom.om.impl.OMNodeEx;
import org.apache.axiom.om.impl.common.IContainer;
import org.apache.axiom.om.impl.common.OMContainerHelper;
import org.apache.axiom.om.impl.common.OMDocumentImplUtil;
import org.apache.axiom.om.impl.common.OMNamespaceImpl;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMException;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
public class DocumentImpl extends RootNode implements Document, OMDocument, IContainer {
protected OMXMLParserWrapper builder;
protected int state;
private String xmlVersion;
private String xmlEncoding;
private boolean xmlStandalone = false;
private String charEncoding;
private Vector idAttrs;
protected Hashtable identifiers;
private final DOMConfigurationImpl domConfig = new DOMConfigurationImpl();
public DocumentImpl(OMXMLParserWrapper parserWrapper, OMFactory factory) {
super(factory);
this.builder = parserWrapper;
}
public DocumentImpl(OMFactory factory) {
super(factory);
state = COMPLETE;
}
ParentNode internalGetOwnerNode() {
return this;
}
void internalSetOwnerNode(ParentNode ownerNode) {
// The owner node of a document node cannot be set
throw new UnsupportedOperationException();
}
public Document getOwnerDocument() {
return null;
}
public void internalSerialize(XMLStreamWriter writer, boolean cache) throws XMLStreamException {
internalSerialize(writer, cache, !((MTOMXMLStreamWriter) writer).isIgnoreXMLDeclaration());
}
// /
// /org.w3c.dom.Node methods
// /
public String getNodeName() {
return "#document";
}
public short getNodeType() {
return Node.DOCUMENT_NODE;
}
// /org.w3c.dom.Document methods
// /
public Attr createAttribute(String name) throws DOMException {
if (!DOMUtil.isQualifiedName(name)) {
throw DOMUtil.newDOMException(DOMException.INVALID_CHARACTER_ERR);
}
return new AttrImpl(this, name, this.factory);
}
public Attr createAttributeNS(String namespaceURI, String qualifiedName)
throws DOMException {
String localName = DOMUtil.getLocalName(qualifiedName);
String prefix = DOMUtil.getPrefix(qualifiedName);
DOMUtil.validateAttrNamespace(namespaceURI, localName, prefix);
if (!XMLConstants.XMLNS_ATTRIBUTE.equals(localName)) {
this.checkQName(prefix, localName);
}
OMNamespace namespace;
if (namespaceURI == null) {
namespace = null;
} else {
namespace = new OMNamespaceImpl(namespaceURI,
prefix == null && !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI) ? "" : prefix);
}
return new AttrImpl(this, localName, namespace, this.factory);
}
public CDATASection createCDATASection(String data) throws DOMException {
CDATASectionImpl cdataSection = new CDATASectionImpl(data, factory);
cdataSection.setOwnerDocument(this);
return cdataSection;
}
public Comment createComment(String data) {
CommentImpl comment = new CommentImpl(data, this.factory);
comment.setOwnerDocument(this);
return comment;
}
public DocumentFragment createDocumentFragment() {
DocumentFragmentImpl fragment = new DocumentFragmentImpl(this.factory);
fragment.setOwnerDocument(this);
return fragment;
}
public Element createElement(String tagName) throws DOMException {
ElementImpl element = new ElementImpl(null, tagName, null, null, this.factory, false);
element.setOwnerDocument(this);
return element;
}
public Element createElementNS(String ns, String qualifiedName)
throws DOMException {
if (ns == null) ns = "";
String localName = DOMUtil.getLocalName(qualifiedName);
String prefix = DOMUtil.getPrefix(qualifiedName);
checkQName(prefix, localName);
if(prefix == null) {
prefix = "";
}
OMNamespaceImpl namespace;
if (ns.length() == 0) {
namespace = null;
} else {
namespace = new OMNamespaceImpl(ns, prefix);
}
ElementImpl element = new ElementImpl(null, localName, namespace, null, this.factory, false);
element.setOwnerDocument(this);
return element;
}
public EntityReference createEntityReference(String name) throws DOMException {
EntityReferenceImpl node = new EntityReferenceImpl(name, null, factory);
node.setOwnerDocument(this);
return node;
}
public ProcessingInstruction createProcessingInstruction(String target,
String data) throws DOMException {
ProcessingInstructionImpl pi = new ProcessingInstructionImpl(target, data, factory);
pi.setOwnerDocument(this);
return pi;
}
public Text createTextNode(String value) {
TextImpl text = new TextImpl(value, this.factory);
text.setOwnerDocument(this);
return text;
}
public DocumentType getDoctype() {
Iterator it = getChildren();
while (it.hasNext()) {
Object child = it.next();
if (child instanceof DocumentType) {
return (DocumentType)child;
} else if (child instanceof Element) {
// A doctype declaration can only appear before the root element. Stop here.
return null;
}
}
return null;
}
public Element getElementById(String elementId) {
//If there are no id attrs
if (this.idAttrs == null) {
return null;
}
Enumeration attrEnum = this.idAttrs.elements();
while (attrEnum.hasMoreElements()) {
Attr tempAttr = (Attr) attrEnum.nextElement();
if (tempAttr.getValue().equals(elementId)) {
return tempAttr.getOwnerElement();
}
}
//If we reach this point then, there's no such attr
return null;
}
public NodeList getElementsByTagName(String tagname) {
// TODO
throw new UnsupportedOperationException("TODO");
}
public NodeList getElementsByTagNameNS(String namespaceURI, String localName) {
// TODO
throw new UnsupportedOperationException("TODO");
}
public DOMImplementation getImplementation() {
return ((DOMMetaFactory)factory.getMetaFactory()).getDOMImplementation();
}
public Node importNode(Node importedNode, boolean deep) throws DOMException {
short type = importedNode.getNodeType();
Node newNode = null;
switch (type) {
case Node.ELEMENT_NODE: {
Element newElement;
if (importedNode.getLocalName() == null) {
newElement = this.createElement(importedNode.getNodeName());
} else {
String ns = importedNode.getNamespaceURI();
ns = (ns != null) ? ns.intern() : null;
newElement = createElementNS(ns, importedNode.getNodeName());
}
// Copy element's attributes, if any.
NamedNodeMap sourceAttrs = importedNode.getAttributes();
if (sourceAttrs != null) {
int length = sourceAttrs.getLength();
for (int index = 0; index < length; index++) {
Attr attr = (Attr) sourceAttrs.item(index);
if (attr.getNamespaceURI() != null
&& !attr.getNamespaceURI().equals(
XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
Attr newAttr = (Attr) importNode(attr, true);
newElement.setAttributeNodeNS(newAttr);
} else { // if (attr.getLocalName() == null) {
Attr newAttr = (Attr) importNode(attr, true);
newElement.setAttributeNode(newAttr);
}
}
}
newNode = newElement;
break;
}
case Node.ATTRIBUTE_NODE: {
if ("".equals(importedNode.getNamespaceURI())
|| importedNode.getNamespaceURI() == null) {
newNode = createAttribute(importedNode.getNodeName());
} else {
//Check whether it is a default ns decl
if (XMLConstants.XMLNS_ATTRIBUTE.equals(importedNode.getNodeName())) {
newNode = createAttribute(importedNode.getNodeName());
} else {
String ns = importedNode.getNamespaceURI();
ns = (ns != null) ? ns.intern() : null;
newNode = createAttributeNS(ns ,
importedNode.getNodeName());
}
}
((Attr) newNode).setValue(importedNode.getNodeValue());
break;
}
case Node.TEXT_NODE: {
newNode = createTextNode(importedNode.getNodeValue());
break;
}
case Node.COMMENT_NODE: {
newNode = createComment(importedNode.getNodeValue());
break;
}
case Node.DOCUMENT_FRAGMENT_NODE: {
newNode = createDocumentFragment();
// No name, kids carry value
break;
}
case Node.CDATA_SECTION_NODE:
case Node.ENTITY_REFERENCE_NODE:
case Node.ENTITY_NODE:
case Node.PROCESSING_INSTRUCTION_NODE:
case Node.DOCUMENT_TYPE_NODE:
case Node.NOTATION_NODE:
throw new UnsupportedOperationException("TODO : Implement handling of org.w3c.dom.Node type == " + type );
case Node.DOCUMENT_NODE: // Can't import document nodes
default:
throw DOMUtil.newDOMException(DOMException.NOT_SUPPORTED_ERR);
}
// If deep, replicate and attach the kids.
if (deep && !(importedNode instanceof Attr)) {
for (Node srckid = importedNode.getFirstChild(); srckid != null;
srckid = srckid.getNextSibling()) {
newNode.appendChild(importNode(srckid, true));
}
}
return newNode;
}
// /
// /OMDocument Methods
// /
public String getCharsetEncoding() {
return this.charEncoding;
}
public String getXMLVersion() {
return this.xmlVersion;
}
public String isStandalone() {
return (this.xmlStandalone) ? "yes" : "no";
}
public void setCharsetEncoding(String charsetEncoding) {
this.charEncoding = charsetEncoding;
}
public void setOMDocumentElement(OMElement documentElement) {
if (documentElement == null) {
throw new IllegalArgumentException("documentElement must not be null");
}
OMElement existingDocumentElement = getOMDocumentElement();
if (existingDocumentElement == null) {
addChild(documentElement);
} else {
OMNode nextSibling = existingDocumentElement.getNextOMSibling();
existingDocumentElement.detach();
if (nextSibling == null) {
addChild(documentElement);
} else {
nextSibling.insertSiblingBefore(documentElement);
}
}
}
public void setStandalone(String isStandalone) {
this.xmlStandalone = "yes".equalsIgnoreCase(isStandalone);
}
public void serializeAndConsume(OutputStream output, OMOutputFormat format)
throws XMLStreamException {
MTOMXMLStreamWriter writer = new MTOMXMLStreamWriter(output, format);
internalSerialize(writer, false);
writer.flush();
}
public void serialize(OutputStream output, OMOutputFormat format) throws XMLStreamException {
MTOMXMLStreamWriter writer = new MTOMXMLStreamWriter(output, format);
internalSerialize(writer, true);
writer.flush();
}
public void setXMLVersion(String version) {
this.xmlVersion = version;
}
public String getXMLEncoding() {
return xmlEncoding;
}
public void setXMLEncoding(String encoding) {
this.xmlEncoding = encoding;
}
public OMElement getOMDocumentElement() {
return getOMDocumentElement(true);
}
OMElement getOMDocumentElement(boolean build) {
OMNode child = build ? getFirstOMChild() : getFirstOMChildIfAvailable();
while (child != null) {
if (child instanceof OMElement) {
return (OMElement)child;
}
child = build ? child.getNextOMSibling() : ((OMNodeEx)child).getNextOMSiblingIfAvailable();
}
return null;
}
/**
* Returns the document element.
*
* @see org.w3c.dom.Document#getDocumentElement()
*/
public Element getDocumentElement() {
return (Element) this.getOMDocumentElement();
}
/**
* Borrowed from the Xerces impl. Checks if the given qualified name is legal with respect to
* the version of XML to which this document must conform.
*
* @param prefix prefix of qualified name
* @param local local part of qualified name
*/
protected final void checkQName(String prefix, String local) {
// check that both prefix and local part match NCName
if ((prefix != null && !XMLChar.isValidNCName(prefix))
|| !XMLChar.isValidNCName(local)) {
throw DOMUtil.newDOMException(DOMException.INVALID_CHARACTER_ERR);
}
}
protected void addIdAttr(Attr attr) {
if (this.idAttrs == null) {
this.idAttrs = new Vector();
}
this.idAttrs.add(attr);
}
protected void removeIdAttr(Attr attr) {
if (this.idAttrs != null) {
this.idAttrs.remove(attr);
}
}
/*
* DOM-Level 3 methods
*/
public String getTextContent() throws DOMException {
return null;
}
public void setTextContent(String textContent) throws DOMException {
// no-op
}
public Node adoptNode(Node node) throws DOMException {
if (node instanceof NodeImpl) {
NodeImpl childNode = (NodeImpl)node;
if (childNode.hasParent()) {
childNode.detach();
}
childNode.setOwnerDocument(this);
return childNode;
} else {
return null;
}
}
public String getDocumentURI() {
// TODO TODO
throw new UnsupportedOperationException("TODO");
}
public DOMConfiguration getDomConfig() {
return domConfig;
}
public String getInputEncoding() {
// TODO TODO
throw new UnsupportedOperationException("TODO");
}
public boolean getStrictErrorChecking() {
// TODO TODO
throw new UnsupportedOperationException("TODO");
}
public String getXmlEncoding() {
return this.charEncoding;
}
public boolean getXmlStandalone() {
return this.xmlStandalone;
}
public String getXmlVersion() {
return getXMLVersion();
}
public void normalizeDocument() {
if (domConfig.isEnabled(DOMConfigurationImpl.SPLIT_CDATA_SECTIONS)
|| domConfig.isEnabled(DOMConfigurationImpl.WELLFORMED)) {
throw new UnsupportedOperationException("TODO");
} else {
normalize(domConfig);
}
}
public Node renameNode(Node node, String namespaceURI, String qualifiedName)
throws DOMException {
// TODO TODO
throw new UnsupportedOperationException("TODO");
}
public void setDocumentURI(String documentURI) {
// TODO TODO
throw new UnsupportedOperationException("TODO");
}
public void setStrictErrorChecking(boolean strictErrorChecking) {
// TODO TODO
throw new UnsupportedOperationException("TODO");
}
public void setXmlStandalone(boolean standalone) throws DOMException {
this.xmlStandalone = standalone;
}
public void setXmlVersion(String version) throws DOMException {
setXMLVersion(version);
}
protected void internalSerialize(XMLStreamWriter writer, boolean cache,
boolean includeXMLDeclaration) throws XMLStreamException {
OMDocumentImplUtil.internalSerialize(this, writer, cache, includeXMLDeclaration);
}
ParentNode shallowClone(OMCloneOptions options, ParentNode targetParent, boolean namespaceRepairing) {
DocumentImpl clone;
if (options.isPreserveModel()) {
clone = createClone(options);
} else {
clone = new DocumentImpl(getOMFactory());
}
clone.xmlVersion = xmlVersion;
clone.xmlEncoding = xmlEncoding;
clone.xmlStandalone = xmlStandalone;
clone.charEncoding = charEncoding;
return clone;
}
protected DocumentImpl createClone(OMCloneOptions options) {
return new DocumentImpl(factory);
}
public final OMXMLParserWrapper getBuilder() {
return builder;
}
public final int getState() {
return state;
}
public final boolean isComplete() {
return state == COMPLETE;
}
public final void setComplete(boolean complete) {
state = complete ? COMPLETE : INCOMPLETE;
}
public final void discarded() {
state = DISCARDED;
}
public final void build() {
OMContainerHelper.build(this);
}
public final Node getNextSibling() {
return null;
}
public final void removeChildren() {
OMContainerHelper.removeChildren(this);
}
public final String lookupNamespaceURI(String specifiedPrefix) {
Element documentElement = getDocumentElement();
return documentElement == null ? null
: documentElement.lookupNamespaceURI(specifiedPrefix);
}
public final void checkChild(OMNode child) {
if (child instanceof OMElement) {
if (getOMDocumentElement() != null) {
throw new OMException("Document element already exists");
} else {
checkDocumentElement((OMElement)child);
}
}
}
protected void checkDocumentElement(OMElement element) {
}
}