org.mozilla.javascript.xmlimpl.XmlNode Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhino Show documentation
Show all versions of rhino Show documentation
Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically
embedded into Java applications to provide scripting to end users.
The newest version!
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.javascript.xmlimpl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mozilla.javascript.Undefined;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.UserDataHandler;
class XmlNode implements Serializable {
private static final long serialVersionUID = 1L;
private static final String XML_NAMESPACES_NAMESPACE_URI = "http://www.w3.org/2000/xmlns/";
private static final String USER_DATA_XMLNODE_KEY = XmlNode.class.getName();
private static final boolean DOM_LEVEL_3 = true;
private static XmlNode getUserData(Node node) {
if (DOM_LEVEL_3) {
return (XmlNode) node.getUserData(USER_DATA_XMLNODE_KEY);
}
return null;
}
private static void setUserData(Node node, XmlNode wrap) {
if (DOM_LEVEL_3) {
node.setUserData(USER_DATA_XMLNODE_KEY, wrap, wrap.events);
}
}
private static XmlNode createImpl(Node node) {
if (node instanceof Document) throw new IllegalArgumentException();
XmlNode rv = null;
if (getUserData(node) == null) {
rv = new XmlNode();
rv.dom = node;
setUserData(node, rv);
} else {
rv = getUserData(node);
}
return rv;
}
static XmlNode newElementWithText(
XmlProcessor processor, XmlNode reference, XmlNode.QName qname, String value) {
if (reference instanceof org.w3c.dom.Document)
throw new IllegalArgumentException("Cannot use Document node as reference");
Document document = null;
if (reference != null) {
document = reference.dom.getOwnerDocument();
} else {
document = processor.newDocument();
}
Node referenceDom = (reference != null) ? reference.dom : null;
Namespace ns = qname.getNamespace();
Element e =
(ns == null || ns.getUri().length() == 0)
? document.createElementNS(null, qname.getLocalName())
: document.createElementNS(ns.getUri(), qname.qualify(referenceDom));
if (value != null) {
e.appendChild(document.createTextNode(value));
}
return XmlNode.createImpl(e);
}
static XmlNode createText(XmlProcessor processor, String value) {
return createImpl(processor.newDocument().createTextNode(value));
}
static XmlNode createElementFromNode(Node node) {
if (node instanceof Document) node = ((Document) node).getDocumentElement();
return createImpl(node);
}
static XmlNode createElement(XmlProcessor processor, String namespaceUri, String xml)
throws org.xml.sax.SAXException {
return createImpl(processor.toXml(namespaceUri, xml));
}
static XmlNode createEmpty(XmlProcessor processor) {
return createText(processor, "");
}
private static XmlNode copy(XmlNode other) {
return createImpl(other.dom.cloneNode(true));
}
private UserDataHandler events = new XmlNodeUserDataHandler();
private Node dom;
private XML xml;
private XmlNode() {}
String debug() {
XmlProcessor raw = new XmlProcessor();
raw.setIgnoreComments(false);
raw.setIgnoreProcessingInstructions(false);
raw.setIgnoreWhitespace(false);
raw.setPrettyPrinting(false);
return raw.ecmaToXmlString(this.dom);
}
@Override
public String toString() {
return "XmlNode: type=" + dom.getNodeType() + " dom=" + dom.toString();
}
XML getXml() {
return xml;
}
void setXml(XML xml) {
this.xml = xml;
}
int getChildCount() {
return this.dom.getChildNodes().getLength();
}
XmlNode parent() {
Node domParent = dom.getParentNode();
if (domParent instanceof Document) return null;
if (domParent == null) return null;
return createImpl(domParent);
}
int getChildIndex() {
if (this.isAttributeType()) return -1;
if (parent() == null) return -1;
org.w3c.dom.NodeList siblings = this.dom.getParentNode().getChildNodes();
for (int i = 0; i < siblings.getLength(); i++) {
if (siblings.item(i) == dom) {
return i;
}
}
// Either the parent is -1 or one of the this node's parent's children is this node.
throw new RuntimeException("Unreachable.");
}
void removeChild(int index) {
this.dom.removeChild(this.dom.getChildNodes().item(index));
}
String toXmlString(XmlProcessor processor) {
return processor.ecmaToXmlString(this.dom);
}
String ecmaValue() {
// TODO See ECMA 357 Section 9.1
if (isTextType()) {
return ((org.w3c.dom.Text) dom).getData();
} else if (isAttributeType()) {
return ((org.w3c.dom.Attr) dom).getValue();
} else if (isProcessingInstructionType()) {
return ((org.w3c.dom.ProcessingInstruction) dom).getData();
} else if (isCommentType()) {
return ((org.w3c.dom.Comment) dom).getNodeValue();
} else if (isElementType()) {
throw new RuntimeException("Unimplemented ecmaValue() for elements.");
} else {
throw new RuntimeException("Unimplemented for node " + dom);
}
}
void deleteMe() {
if (dom instanceof Attr) {
Attr attr = (Attr) this.dom;
attr.getOwnerElement()
.getAttributes()
.removeNamedItemNS(attr.getNamespaceURI(), attr.getLocalName());
} else {
if (this.dom.getParentNode() != null) {
this.dom.getParentNode().removeChild(this.dom);
} else {
// This case can be exercised at least when executing the regression
// tests under https://bugzilla.mozilla.org/show_bug.cgi?id=354145
}
}
}
void normalize() {
this.dom.normalize();
}
void insertChildAt(int index, XmlNode node) {
Node parent = this.dom;
Node child = parent.getOwnerDocument().importNode(node.dom, true);
if (parent.getChildNodes().getLength() < index) {
// TODO Check ECMA for what happens here
throw new IllegalArgumentException(
"index=" + index + " length=" + parent.getChildNodes().getLength());
}
if (parent.getChildNodes().getLength() == index) {
parent.appendChild(child);
} else {
parent.insertBefore(child, parent.getChildNodes().item(index));
}
}
void insertChildrenAt(int index, XmlNode[] nodes) {
for (int i = 0; i < nodes.length; i++) {
insertChildAt(index + i, nodes[i]);
}
}
XmlNode getChild(int index) {
Node child = dom.getChildNodes().item(index);
return createImpl(child);
}
// Helper method for XML.hasSimpleContent()
boolean hasChildElement() {
org.w3c.dom.NodeList nodes = this.dom.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i).getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) return true;
}
return false;
}
boolean isSameNode(XmlNode other) {
// TODO May need to be changed if we allow XmlNode to refer to several Node objects
return this.dom == other.dom;
}
private String toUri(String ns) {
return (ns == null) ? "" : ns;
}
private void addNamespaces(Namespaces rv, Element element) {
if (element == null) throw new RuntimeException("element must not be null");
String myDefaultNamespace = toUri(element.lookupNamespaceURI(null));
String parentDefaultNamespace = "";
if (element.getParentNode() != null) {
parentDefaultNamespace = toUri(element.getParentNode().lookupNamespaceURI(null));
}
if (!myDefaultNamespace.equals(parentDefaultNamespace)
|| !(element.getParentNode() instanceof Element)) {
rv.declare(Namespace.create("", myDefaultNamespace));
}
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Attr attr = (Attr) attributes.item(i);
if (attr.getPrefix() != null && attr.getPrefix().equals("xmlns")) {
rv.declare(Namespace.create(attr.getLocalName(), attr.getValue()));
}
}
}
private Namespaces getAllNamespaces() {
Namespaces rv = new Namespaces();
Node target = this.dom;
if (target instanceof Attr) {
target = ((Attr) target).getOwnerElement();
}
while (target != null) {
if (target instanceof Element) {
addNamespaces(rv, (Element) target);
}
target = target.getParentNode();
}
// Fallback in case no namespace was declared
rv.declare(Namespace.create("", ""));
return rv;
}
Namespace[] getInScopeNamespaces() {
Namespaces rv = getAllNamespaces();
return rv.getNamespaces();
}
Namespace[] getNamespaceDeclarations() {
// ECMA357 13.4.4.24
if (this.dom instanceof Element) {
Namespaces rv = new Namespaces();
addNamespaces(rv, (Element) this.dom);
return rv.getNamespaces();
} else {
return new Namespace[0];
}
}
Namespace getNamespaceDeclaration(String prefix) {
if (prefix.equals("") && dom instanceof Attr) {
// Default namespaces do not apply to attributes; see XML Namespaces section 5.2
return Namespace.create("", "");
}
Namespaces rv = getAllNamespaces();
return rv.getNamespace(prefix);
}
Namespace getNamespaceDeclaration() {
if (dom.getPrefix() == null) return getNamespaceDeclaration("");
return getNamespaceDeclaration(dom.getPrefix());
}
static class XmlNodeUserDataHandler implements UserDataHandler, Serializable {
private static final long serialVersionUID = 4666895518900769588L;
@Override
public void handle(short operation, String key, Object data, Node src, Node dest) {}
}
private static class Namespaces {
private Map map = new HashMap();
private Map uriToPrefix = new HashMap();
Namespaces() {}
void declare(Namespace n) {
if (map.get(n.prefix) == null) {
map.put(n.prefix, n.uri);
}
// TODO I think this is analogous to the other way, but have not really thought it
// through ... should local scope
// matter more than outer scope?
if (uriToPrefix.get(n.uri) == null) {
uriToPrefix.put(n.uri, n.prefix);
}
}
Namespace getNamespaceByUri(String uri) {
if (uriToPrefix.get(uri) == null) return null;
return Namespace.create(uri, uriToPrefix.get(uri));
}
Namespace getNamespace(String prefix) {
if (map.get(prefix) == null) return null;
return Namespace.create(prefix, map.get(prefix));
}
Namespace[] getNamespaces() {
ArrayList rv = new ArrayList();
for (Map.Entry e : map.entrySet()) {
Namespace n = Namespace.create(e.getKey(), e.getValue());
if (!n.isEmpty()) {
rv.add(n);
}
}
return rv.toArray(new Namespace[rv.size()]);
}
}
final XmlNode copy() {
return copy(this);
}
// Returns whether this node is capable of being a parent
final boolean isParentType() {
return isElementType();
}
final boolean isTextType() {
return dom.getNodeType() == Node.TEXT_NODE || dom.getNodeType() == Node.CDATA_SECTION_NODE;
}
final boolean isAttributeType() {
return dom.getNodeType() == Node.ATTRIBUTE_NODE;
}
final boolean isProcessingInstructionType() {
return dom.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE;
}
final boolean isCommentType() {
return dom.getNodeType() == Node.COMMENT_NODE;
}
final boolean isElementType() {
return dom.getNodeType() == Node.ELEMENT_NODE;
}
final void renameNode(QName qname) {
this.dom =
dom.getOwnerDocument()
.renameNode(dom, qname.getNamespace().getUri(), qname.qualify(dom));
}
void invalidateNamespacePrefix() {
if (!(dom instanceof Element)) throw new IllegalStateException();
String prefix = this.dom.getPrefix();
QName after = QName.create(this.dom.getNamespaceURI(), this.dom.getLocalName(), null);
renameNode(after);
NamedNodeMap attrs = this.dom.getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
if (attrs.item(i).getPrefix().equals(prefix)) {
createImpl(attrs.item(i))
.renameNode(
QName.create(
attrs.item(i).getNamespaceURI(),
attrs.item(i).getLocalName(),
null));
}
}
}
private void declareNamespace(Element e, String prefix, String uri) {
if (prefix.length() > 0) {
e.setAttributeNS(XML_NAMESPACES_NAMESPACE_URI, "xmlns:" + prefix, uri);
} else {
e.setAttribute("xmlns", uri);
}
}
void declareNamespace(String prefix, String uri) {
if (!(dom instanceof Element)) throw new IllegalStateException();
if (dom.lookupNamespaceURI(uri) != null && dom.lookupNamespaceURI(uri).equals(prefix)) {
// do nothing
} else {
Element e = (Element) dom;
declareNamespace(e, prefix, uri);
}
}
private Namespace getDefaultNamespace() {
String prefix = "";
String uri = (dom.lookupNamespaceURI(null) == null) ? "" : dom.lookupNamespaceURI(null);
return Namespace.create(prefix, uri);
}
private String getExistingPrefixFor(Namespace namespace) {
if (getDefaultNamespace().getUri().equals(namespace.getUri())) {
return "";
}
return dom.lookupPrefix(namespace.getUri());
}
private Namespace getNodeNamespace() {
String uri = dom.getNamespaceURI();
String prefix = dom.getPrefix();
if (uri == null) uri = "";
if (prefix == null) prefix = "";
return Namespace.create(prefix, uri);
}
Namespace getNamespace() {
return getNodeNamespace();
}
void removeNamespace(Namespace namespace) {
Namespace current = getNodeNamespace();
// Do not remove in-use namespace
if (namespace.is(current)) return;
NamedNodeMap attrs = this.dom.getAttributes();
for (int i = 0; i < attrs.getLength(); i++) {
XmlNode attr = XmlNode.createImpl(attrs.item(i));
if (namespace.is(attr.getNodeNamespace())) return;
}
// TODO I must confess I am not sure I understand the spec fully. See ECMA357
// 13.4.4.31
String existingPrefix = getExistingPrefixFor(namespace);
if (existingPrefix != null) {
if (namespace.isUnspecifiedPrefix()) {
// we should remove any namespace with this URI from scope; we do this by
// declaring a namespace with the same
// prefix as the existing prefix and setting its URI to the default namespace
declareNamespace(existingPrefix, getDefaultNamespace().getUri());
} else {
if (existingPrefix.equals(namespace.getPrefix())) {
declareNamespace(existingPrefix, getDefaultNamespace().getUri());
}
}
} else {
// the argument namespace is not declared in this scope, so do nothing.
}
}
private void setProcessingInstructionName(String localName) {
org.w3c.dom.ProcessingInstruction pi = (ProcessingInstruction) this.dom;
// We cannot set the node name; Document.renameNode() only supports elements and
// attributes. So we replace it
pi.getParentNode()
.replaceChild(
pi,
pi.getOwnerDocument().createProcessingInstruction(localName, pi.getData()));
}
final void setLocalName(String localName) {
if (dom instanceof ProcessingInstruction) {
setProcessingInstructionName(localName);
} else {
String prefix = dom.getPrefix();
if (prefix == null) prefix = "";
this.dom =
dom.getOwnerDocument()
.renameNode(
dom, dom.getNamespaceURI(), QName.qualify(prefix, localName));
}
}
final QName getQname() {
String uri = (dom.getNamespaceURI()) == null ? "" : dom.getNamespaceURI();
String prefix = (dom.getPrefix() == null) ? "" : dom.getPrefix();
return QName.create(uri, dom.getLocalName(), prefix);
}
void addMatchingChildren(XMLList result, XmlNode.Filter filter) {
Node node = this.dom;
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node childnode = children.item(i);
XmlNode child = XmlNode.createImpl(childnode);
if (filter.accept(childnode)) {
result.addToList(child);
}
}
}
XmlNode[] getMatchingChildren(Filter filter) {
ArrayList rv = new ArrayList();
NodeList nodes = this.dom.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (filter.accept(node)) {
rv.add(createImpl(node));
}
}
return rv.toArray(new XmlNode[rv.size()]);
}
XmlNode[] getAttributes() {
NamedNodeMap attrs = this.dom.getAttributes();
// TODO Or could make callers handle null?
if (attrs == null) throw new IllegalStateException("Must be element.");
XmlNode[] rv = new XmlNode[attrs.getLength()];
for (int i = 0; i < attrs.getLength(); i++) {
rv[i] = createImpl(attrs.item(i));
}
return rv;
}
String getAttributeValue() {
return ((Attr) dom).getValue();
}
void setAttribute(QName name, String value) {
if (!(dom instanceof Element))
throw new IllegalStateException("Can only set attribute on elements.");
name.setAttribute((Element) dom, value);
}
void replaceWith(XmlNode other) {
Node replacement = this.dom.getOwnerDocument().importNode(other.dom, true);
this.dom.getParentNode().replaceChild(replacement, this.dom);
}
String ecmaToXMLString(XmlProcessor processor) {
if (this.isElementType()) {
Element copy = (Element) this.dom.cloneNode(true);
Namespace[] inScope = this.getInScopeNamespaces();
for (int i = 0; i < inScope.length; i++) {
declareNamespace(copy, inScope[i].getPrefix(), inScope[i].getUri());
}
return processor.ecmaToXmlString(copy);
} else {
return processor.ecmaToXmlString(dom);
}
}
static class Namespace implements Serializable {
/** Serial version id for Namespace with fields prefix and uri */
private static final long serialVersionUID = 4073904386884677090L;
static Namespace create(String prefix, String uri) {
if (prefix == null) {
throw new IllegalArgumentException(
"Empty string represents default namespace prefix");
}
if (uri == null) {
throw new IllegalArgumentException("Namespace may not lack a URI");
}
Namespace rv = new Namespace();
rv.prefix = prefix;
rv.uri = uri;
return rv;
}
static Namespace create(String uri) {
Namespace rv = new Namespace();
rv.uri = uri;
// Avoid null prefix for "" namespace
if (uri == null || uri.length() == 0) {
rv.prefix = "";
}
return rv;
}
static final Namespace GLOBAL = create("", "");
private String prefix;
private String uri;
private Namespace() {}
@Override
public String toString() {
if (prefix == null) return "XmlNode.Namespace [" + uri + "]";
return "XmlNode.Namespace [" + prefix + "{" + uri + "}]";
}
boolean isUnspecifiedPrefix() {
return prefix == null;
}
boolean is(Namespace other) {
return this.prefix != null
&& other.prefix != null
&& this.prefix.equals(other.prefix)
&& this.uri.equals(other.uri);
}
boolean isEmpty() {
return prefix != null && prefix.equals("") && uri.equals("");
}
boolean isDefault() {
return prefix != null && prefix.equals("");
}
boolean isGlobal() {
return uri != null && uri.equals("");
}
// Called by QName
// TODO Move functionality from QName lookupPrefix to here
private void setPrefix(String prefix) {
if (prefix == null) throw new IllegalArgumentException();
this.prefix = prefix;
}
String getPrefix() {
return prefix;
}
String getUri() {
return uri;
}
}
// TODO Where is this class used? No longer using it in QName implementation
static class QName implements Serializable {
private static final long serialVersionUID = -6587069811691451077L;
static QName create(Namespace namespace, String localName) {
// A null namespace indicates a wild-card match for any namespace
// A null localName indicates "*" from the point of view of ECMA357
if (localName != null && localName.equals("*"))
throw new RuntimeException("* is not valid localName");
QName rv = new QName();
rv.namespace = namespace;
rv.localName = localName;
return rv;
}
/** @deprecated */
@Deprecated
static QName create(String uri, String localName, String prefix) {
return create(Namespace.create(prefix, uri), localName);
}
static String qualify(String prefix, String localName) {
if (prefix == null) throw new IllegalArgumentException("prefix must not be null");
if (prefix.length() > 0) return prefix + ":" + localName;
return localName;
}
private Namespace namespace;
private String localName;
private QName() {}
@Override
public String toString() {
return "XmlNode.QName [" + localName + "," + namespace + "]";
}
private boolean equals(String one, String two) {
if (one == null && two == null) return true;
if (one == null || two == null) return false;
return one.equals(two);
}
private boolean namespacesEqual(Namespace one, Namespace two) {
if (one == null && two == null) return true;
if (one == null || two == null) return false;
return equals(one.getUri(), two.getUri());
}
final boolean equals(QName other) {
if (!namespacesEqual(this.namespace, other.namespace)) return false;
if (!equals(this.localName, other.localName)) return false;
return true;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof QName)) {
return false;
}
return equals((QName) obj);
}
@Override
public int hashCode() {
return localName == null ? 0 : localName.hashCode();
}
void lookupPrefix(org.w3c.dom.Node node) {
if (node == null) throw new IllegalArgumentException("node must not be null");
String prefix = node.lookupPrefix(namespace.getUri());
if (prefix == null) {
// check to see if we match the default namespace
String defaultNamespace = node.lookupNamespaceURI(null);
if (defaultNamespace == null) defaultNamespace = "";
String nodeNamespace = namespace.getUri();
if (nodeNamespace.equals(defaultNamespace)) {
prefix = "";
}
}
int i = 0;
while (prefix == null) {
String generatedPrefix = "e4x_" + i++;
String generatedUri = node.lookupNamespaceURI(generatedPrefix);
if (generatedUri == null) {
prefix = generatedPrefix;
org.w3c.dom.Node top = node;
while (top.getParentNode() != null
&& top.getParentNode() instanceof org.w3c.dom.Element) {
top = top.getParentNode();
}
((org.w3c.dom.Element) top)
.setAttributeNS(
"http://www.w3.org/2000/xmlns/",
"xmlns:" + prefix,
namespace.getUri());
}
}
namespace.setPrefix(prefix);
}
String qualify(org.w3c.dom.Node node) {
if (namespace.getPrefix() == null) {
if (node != null) {
lookupPrefix(node);
} else {
namespace.setPrefix("");
}
}
return qualify(namespace.getPrefix(), localName);
}
void setAttribute(org.w3c.dom.Element element, String value) {
if (namespace.getPrefix() == null) lookupPrefix(element);
element.setAttributeNS(
namespace.getUri(), qualify(namespace.getPrefix(), localName), value);
}
Namespace getNamespace() {
return namespace;
}
String getLocalName() {
return localName;
}
}
static class InternalList implements Serializable {
private static final long serialVersionUID = -3633151157292048978L;
private List list;
InternalList() {
list = new ArrayList();
}
private void _add(XmlNode n) {
list.add(n);
}
XmlNode item(int index) {
return list.get(index);
}
void remove(int index) {
list.remove(index);
}
void add(InternalList other) {
for (int i = 0; i < other.length(); i++) {
_add(other.item(i));
}
}
void add(InternalList from, int startInclusive, int endExclusive) {
for (int i = startInclusive; i < endExclusive; i++) {
_add(from.item(i));
}
}
void add(XmlNode node) {
_add(node);
}
/* TODO: was marked deprecated by original author */
void add(XML xml) {
_add(xml.getAnnotation());
}
/* TODO: was marked deprecated by original author */
void addToList(Object toAdd) {
if (toAdd instanceof Undefined) {
// Missing argument do nothing...
return;
}
if (toAdd instanceof XMLList) {
XMLList xmlSrc = (XMLList) toAdd;
for (int i = 0; i < xmlSrc.length(); i++) {
this._add((xmlSrc.item(i)).getAnnotation());
}
} else if (toAdd instanceof XML) {
this._add(((XML) (toAdd)).getAnnotation());
} else if (toAdd instanceof XmlNode) {
this._add((XmlNode) toAdd);
}
}
int length() {
return list.size();
}
}
abstract static class Filter {
static final Filter COMMENT =
new Filter() {
@Override
boolean accept(Node node) {
return node.getNodeType() == Node.COMMENT_NODE;
}
};
static final Filter TEXT =
new Filter() {
@Override
boolean accept(Node node) {
return node.getNodeType() == Node.TEXT_NODE;
}
};
static Filter PROCESSING_INSTRUCTION(final XMLName name) {
return new Filter() {
@Override
boolean accept(Node node) {
if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
ProcessingInstruction pi = (ProcessingInstruction) node;
return name.matchesLocalName(pi.getTarget());
}
return false;
}
};
}
static Filter ELEMENT =
new Filter() {
@Override
boolean accept(Node node) {
return node.getNodeType() == Node.ELEMENT_NODE;
}
};
static Filter TRUE =
new Filter() {
@Override
boolean accept(Node node) {
return true;
}
};
abstract boolean accept(Node node);
}
// Support experimental Java interface
org.w3c.dom.Node toDomNode() {
return this.dom;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy