blob: 344c9bf6d01655c7bfd50eddcafecf4cdbda60c1 [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.truth.xml;
import java.util.HashMap;
import java.util.Map;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import org.apache.axiom.truth.xml.spi.Event;
import org.apache.axiom.truth.xml.spi.Traverser;
import org.w3c.dom.Attr;
import org.w3c.dom.DocumentType;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import com.google.common.base.Strings;
final class DOMTraverser implements Traverser {
private final Node root;
private final boolean dom3;
private final boolean expandEntityReferences;
private Node node;
private boolean descend;
DOMTraverser(Node root, boolean dom3, boolean expandEntityReferences) {
this.root = root;
this.dom3 = dom3;
this.expandEntityReferences = expandEntityReferences;
if (root.getNodeType() == Node.DOCUMENT_NODE) {
node = root;
descend = true;
}
}
@Override
public Event next() {
while (true) {
boolean visited;
if (node == null) {
node = root;
visited = false;
} else if (descend) {
Node firstChild = node.getFirstChild();
if (firstChild != null) {
node = firstChild;
visited = false;
} else {
visited = true;
}
} else {
Node nextSibling = node.getNextSibling();
if (node == root) {
return null;
} else if (nextSibling != null) {
node = nextSibling;
visited = false;
} else {
node = node.getParentNode();
visited = true;
}
}
switch (node.getNodeType()) {
case Node.DOCUMENT_NODE:
return null;
case Node.DOCUMENT_TYPE_NODE:
descend = false;
return Event.DOCUMENT_TYPE;
case Node.ELEMENT_NODE:
if (!visited) {
descend = true;
return Event.START_ELEMENT;
} else {
descend = false;
return Event.END_ELEMENT;
}
case Node.TEXT_NODE:
descend = false;
return dom3 && ((Text)node).isElementContentWhitespace() ? Event.WHITESPACE : Event.TEXT;
case Node.ENTITY_REFERENCE_NODE:
if (expandEntityReferences) {
descend = !visited;
break;
} else {
descend = false;
return Event.ENTITY_REFERENCE;
}
case Node.COMMENT_NODE:
descend = false;
return Event.COMMENT;
case Node.CDATA_SECTION_NODE:
descend = false;
return Event.CDATA_SECTION;
case Node.PROCESSING_INSTRUCTION_NODE:
descend = false;
return Event.PROCESSING_INSTRUCTION;
default:
throw new IllegalStateException();
}
}
}
@Override
public String getRootName() {
return ((DocumentType)node).getName();
}
@Override
public String getPublicId() {
return ((DocumentType)node).getPublicId();
}
@Override
public String getSystemId() {
return ((DocumentType)node).getSystemId();
}
private static QName getQName(Node node) {
String localName = node.getLocalName();
if (localName == null) {
return new QName(node.getNodeName());
} else {
return new QName(node.getNamespaceURI(), node.getLocalName(), Strings.nullToEmpty(node.getPrefix()));
}
}
@Override
public QName getQName() {
return getQName(node);
}
@Override
public Map<QName,String> getAttributes() {
Map<QName,String> result = null;
NamedNodeMap attributes = node.getAttributes();
for (int i=0; i<attributes.getLength(); i++) {
Attr attr = (Attr)attributes.item(i);
if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.getNamespaceURI())) {
if (result == null) {
result = new HashMap<>();
}
result.put(getQName(attr), attr.getValue());
}
}
return result;
}
@Override
public Map<String,String> getNamespaces() {
Map<String,String> result = null;
NamedNodeMap attributes = node.getAttributes();
for (int i=0; i<attributes.getLength(); i++) {
Attr attr = (Attr)attributes.item(i);
if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.getNamespaceURI())) {
if (result == null) {
result = new HashMap<>();
}
String prefix = attr.getPrefix();
result.put(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) ? attr.getLocalName() : "", attr.getValue());
}
}
return result;
}
@Override
public String getText() {
return node.getNodeValue();
}
@Override
public String getEntityName() {
return node.getNodeName();
}
@Override
public String getPITarget() {
return ((ProcessingInstruction)node).getTarget();
}
@Override
public String getPIData() {
return ((ProcessingInstruction)node).getData();
}
}