All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.dom.ElementImpl Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2009 Adobe Systems Incorporated All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Adobe Systems Incorporated and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Adobe Systems
 * Incorporated and its suppliers and may be covered by U.S. and Foreign
 * Patents, patents in process, and are protected by trade secret or copyright
 * law. Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained from
 * Adobe Systems Incorporated.
 */
package com.adobe.xfa.dom;

import java.util.Iterator;
import java.util.NoSuchElementException;

import org.w3c.dom.Attr;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMException;
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.TypeInfo;
import org.w3c.dom.UserDataHandler;

import com.adobe.xfa.ut.FindBugsSuppress;
import com.adobe.xfa.ut.StringUtils;

/**
 * Implements the W3C DOM Element interface, wrapping an XFA DOM element.
 * @exclude from published api.
 */
class ElementImpl extends ParentNode implements Element {
	static final String ALL_NODES = "*";
	private final QNameImpl mQName;
	private AttrImpl mFirstAttr;
	private AttrImpl mLastAttr;
	private int mAttrCount = -1;
	private NamedNodeMapImpl mAttrMap;

	ElementImpl (ParentNode parent, com.adobe.xfa.Element newElement) {
		super (parent, newElement);
		mQName = new QNameImpl (getXFAElement().getNS(), getXFAElement().getPrefix(), getXFAElement().getLocalName());
		DocumentImpl doc = getDocument();
		if (parent == doc) {
			doc.setDocumentElement (this);
		}
//		debugInit ("Element", mQName.getQName());
//		debugNewChild (parent);
	}

	public String getAttribute(String name) {
//		debugMethod1 ("getAttribute", name);
		Attr attr = getAttributeNode (name);
		return (attr == null) ? null : attr.getValue();
	}

	public String getAttributeNS(String namespaceURI, String localName) throws DOMException {
//		debugMethod2 ("getAttributeNS", namespaceURI, localName);
		Attr attr = getAttributeNodeNS (namespaceURI, localName);
		return (attr == null) ? null : attr.getValue();
	}

	public Attr getAttributeNode(String name) {
//		debugMethod1 ("getAttributeNode", name);
		populateAttrMap();
		Node result = mAttrMap.getNamedItem (name);
		if (result == null) {
			return null;
		}
		assert (result instanceof Attr);
		return (Attr) result;
	}

	public Attr getAttributeNodeNS(String namespaceURI, String localName) throws DOMException {
//		debugMethod2 ("getAttributeNodeNS", namespaceURI, localName);
		populateAttrMap();
		Node result = mAttrMap.getNamedItemNS (namespaceURI, localName);
		if (result == null) {
			return null;
		}
		assert (result instanceof Attr);
		return (Attr) result;
	}

	@FindBugsSuppress(code="ES")
	public NodeList getElementsByTagName(String name) {
//		debugMethod1 ("getElementsByTagName", name);
		name = name.intern();
		NodeListImpl childList = new NodeListImpl (0);
		addChildrenByTagName (name, childList);
		return childList;
	}

	@FindBugsSuppress(code="ES")
	public NodeList getElementsByTagNameNS(String namespaceURI, String localName) throws DOMException {
//		debugMethod2 ("getElementsByTagNameNS", namespaceURI, localName);
		namespaceURI = namespaceURI.intern();
		localName = localName.intern();
		NodeListImpl childList = new NodeListImpl (0);
		addChildrenByTagNameNS (namespaceURI, localName, childList);
		return childList;
	}

	public TypeInfo getSchemaTypeInfo() {
		return null;
	}

	public String getTagName() {
//		debugReturn ("getTagName", mQName.getQName());
		return mQName.getQName();
	}

	public boolean hasAttribute(String name) {
//		debugMethod1 ("hasAttribute", name);
		return getAttributeNode (name) != null;
	}

	public boolean hasAttributeNS(String namespaceURI, String localName) throws DOMException {
//		debugMethod2 ("hasAttributeNS", namespaceURI, localName);
		return getAttributeNodeNS (namespaceURI, localName) != null;
	}

	public void removeAttribute(String name) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void removeAttributeNS(String namespaceURI, String localName) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public Attr removeAttributeNode(Attr oldAttr) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setAttribute(String name, String newValue) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setAttributeNS(String namespaceURI, String localName, String newValue) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public Attr setAttributeNode(Attr newAttr) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public Attr setAttributeNodeNS(Attr newAttr) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setIdAttribute(String name, boolean isId) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setIdAttributeNS(String namespaceURI, String localName, boolean isId) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setIdAttributeNode(Attr idAttr, boolean isId) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public NamedNodeMap getAttributes() {
//		debug ("getAttributes()");
		fillAllAttrs();
		NamedNodeMapImpl namedNodeMap = new NamedNodeMapImpl (getXFAElement().getNumAttrs());
		namedNodeMap.addNodes (mFirstAttr);
		return namedNodeMap;
	}

	public String getLocalName() {
//		debugReturn ("getLocalName", mQName.getLocalName());
		return mQName.getLocalName();
	}

	public String getNamespaceURI() {
//		debugReturn ("getNamespaceURI", mQName.getNamespace());
		return mQName.getNamespace();
	}

	public String getNodeName () {
//		debugReturn ("getNodeName", mQName.getQName());
		return mQName.getQName();
	}

	public short getNodeType() {
		return ELEMENT_NODE;
	}

	public String getPrefix() {
//		debugReturn ("getPrefix", mQName.getPrefix());
		return mQName.getPrefix();
	}

	public String getTextContent() throws DOMException {
		fillAllChildren();
		NodeImpl child = getFirstChildImpl();
		if (child == null) {
			return null;
		}
		StringBuilder resultBuilder = new StringBuilder();
		for (; child != null; child = child.getNext()) {
			if ((! (child instanceof Comment)) && (! (child instanceof ProcessingInstruction))) {
				String childContent = child.getTextContent();
				if (childContent != null) {
					resultBuilder.append (childContent);
				}
			}
		}
		return resultBuilder.toString();
	}

	public Object getUserData(String key) {
		return null;
	}

	public boolean hasAttributes() {
		return getXFAElement().getNumAttrs() > 0;
	}

	public boolean isDefaultNamespace(String namespaceURI) {
		return testDefaultNamespace (namespaceURI);
	}

	public boolean isEqualNode(Node other) {
		if (this == other) {
			return true;
		}
		if (! super.isEqualNode (other)) {
			return false;
		}
		if (! (other instanceof ElementImpl)) {
			return false;
		}

		ElementImpl otherElement = (ElementImpl) other;
		NamedNodeMap thisAttrs = getAttributes();
		NamedNodeMap otherAttrs = otherElement.getAttributes();
		int thisAttrCount = thisAttrs.getLength();
		int otherAttrCount = otherAttrs.getLength();
		if (thisAttrCount != otherAttrCount) {
			return false;
		}
		for (int i = 0; i < thisAttrCount; i++) {
			Node thisAttr = thisAttrs.item (i);
			Node otherAttr = null;
			String thisNS = thisAttr.getNamespaceURI();
			if (StringUtils.isEmpty (thisNS)) {
				otherAttr = otherAttrs.getNamedItem (thisAttr.getNodeName());
			} else {
				otherAttr = otherAttrs.getNamedItemNS (thisNS, thisAttr.getLocalName());
			}
			if (otherAttr == null) {
				return false;
			}
			if (! thisAttr.isEqualNode (otherAttr)) {
				return false;
			}
		}

		return true;
	}

	public String lookupNamespaceURI(String prefix) {
		String result = doLookupNamespaceURI (prefix);
//		debugReturn1 ("lookupNamespaceURI", prefix, result);
		return result;
	}

	public String lookupPrefix(String namespaceURI) {
		String result = doLookupPrefix (namespaceURI, this);
//		debugReturn1 ("lookupPrefix", namespaceURI, result);
		return result;
	}

	public void normalize() {
	}

	public void setNodeValue(String newValue) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setPrefix(String prefix) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public void setTextContent(String textContent) throws DOMException {
		throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, "");
	}

	public Object setUserData(String key, Object data, UserDataHandler handler) {
		return null;
	}

	String doLookupNamespaceURI (String prefix) {
/*
 * Algorithm defined in
 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespaceURIAlgo.
 */
		String result = null;

		if (prefix != null) {
			prefix = prefix.intern();
			if (prefix == mQName.getPrefix()) {
				result = mQName.getNamespace();
			}
		}

		if (result == null) {
			fillAllAttrs();
			for (NodeImpl attrNode = mFirstAttr; attrNode != null; attrNode = attrNode.getNext()) {
				assert (attrNode instanceof AttrImpl);
				AttrImpl attr = (AttrImpl) attrNode;
				if ((attr.isNamespaceAttr (AttrImpl.CHECK_PREFIX) && (attr.getLocalName() == prefix))
				 || ((prefix == null) && attr.isNamespaceAttr (AttrImpl.CHECK_DEFAULT))) {
					String value = attrNode.getNodeValue();
					result = StringUtils.isEmpty (value) ? null : value;
					break;
				}
			}

			if (result == null) {
				ParentNode parent = getParent();
				if (parent instanceof ElementImpl) {
					result = ((ElementImpl)parent).doLookupNamespaceURI (prefix);
				}
			}
		}

//		debugReturn1 ("lookupNamespaceURI", prefix, result);
		return result;
	}

	String doLookupPrefix (String namespaceURI, ElementImpl originalElement) {
/*
 * Algorithm defined in
 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#lookupNamespacePrefixAlgo.
 */
		namespaceURI = namespaceURI.intern();
		String thisNS = mQName.getNamespace();
		String thisPrefix = mQName.getPrefix();
		if ((! StringUtils.isEmpty (thisNS))
		 && (thisNS == namespaceURI)
		 && (namespaceURI == originalElement.lookupNamespaceURI (thisPrefix))) {
			return thisPrefix;
		}

		fillAllAttrs();
		for (NodeImpl attrNode = mFirstAttr; attrNode != null; attrNode = attrNode.getNext()) {
			assert (attrNode instanceof AttrImpl);
			AttrImpl attr = (AttrImpl) attrNode;
			String attrLocalName = attr.getLocalName();
			if ((attr.isPopulated())
			 && (attr.getPrefix() == QNameImpl.XMLNS)
			 && (attr.getNodeValue().equals (namespaceURI))
			 && (lookupNamespaceURI (attrLocalName) == namespaceURI)) {
				 return attrLocalName;
			}
		}

		ParentNode parent = getParent();
		if (parent instanceof ElementImpl) {
			return ((ElementImpl)parent).doLookupPrefix (namespaceURI, originalElement);
		}

		return null;
	}
	
	private static class NamespaceIterator implements Iterator {
		
		private ElementImpl mElement;
		private AttrImpl    mAttr;
		
		public NamespaceIterator(ElementImpl element) {
			mElement = element;			
			mElement.fillAllAttrs();
			mAttr = scanToNextNamespaceAttributeInScope(mElement.mFirstAttr);
		}

		public boolean hasNext() {
			return mAttr != null;
		}

		public AttrImpl next() {
			
			if (mAttr == null)
				throw new NoSuchElementException();
			
			AttrImpl result = mAttr;
			mAttr = scanToNextNamespaceAttributeInScope(mAttr.getNext());
			return result;
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}
		
		private AttrImpl scanToNextNamespaceAttributeInScope(NodeImpl currentChild) {
			
			while (true) {
				
				for (NodeImpl attrNode = currentChild; attrNode != null; attrNode = attrNode.getNext()) {
					if (attrNode instanceof AttrImpl) {
						AttrImpl attr = (AttrImpl)attrNode;
						if (attr.isNamespaceAttr (AttrImpl.CHECK_PREFIX | AttrImpl.CHECK_DEFAULT)) {
							return attr;
						}
					}
				}
				
				ParentNode parent = mElement.getParent();
				if (parent instanceof ElementImpl) {
					mElement = (ElementImpl)parent;
					mElement.fillAllAttrs();
					currentChild = mElement.mFirstAttr;
					//continue;
				}
				else {
					//mElement = null;
					return null;
				}
			}
		}
	}
	
	Iterator getNamespacesInScopeIterator() {
		return new NamespaceIterator(this);
	}

	@FindBugsSuppress(code="ES")
	boolean testDefaultNamespace (String namespaceURI) {
/*
 * Algorithm defined in
 * http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/namespaces-algorithms.html#isDefaultNamespaceAlgo.
 */
//		debugMethod1 ("isDefaultNamespace", namespaceURI);
		if (StringUtils.isEmpty (mQName.getPrefix())) {
			return namespaceURI == mQName.getNamespace();
		}

		fillAllAttrs();
		for (NodeImpl attrNode = mFirstAttr; attrNode != null; attrNode = attrNode.getNext()) {
			assert (attrNode instanceof AttrImpl);
			AttrImpl attr = (AttrImpl) attrNode;
			if (attr.isNamespaceAttr (AttrImpl.CHECK_DEFAULT)) {
				return namespaceURI.equals (attrNode.getNodeValue());
			}
		}

		ParentNode parent = getParent();
		if (parent != null) {
			return parent.testDefaultNamespace (namespaceURI);
		}

		return false;
	}

/*
 * Creates all attribute nodes.  This is typically called immediately
 * before an attribute is needed (e.g., from an API call that requests
 * an attribute).  Unlike child nodes, attributes are all grabbed at
 * once.
 *
 * When an attribute object is created, it is initially "unpopulated".
 * These objects will populate themselves as information is requested
 * from them.  Populating a namespace-related attribute (xmlns) is a
 * relatively simple operation; just fill in the data from the XFA DOM.
 * However, populating a non-namespace attribute may require namespace
 * operations be performed on its containing element hierarchy.	This
 * processing requires that all namespace-related attributes already be
 * present in the containing hierarchy.  So, namespace-related
 * attributes are populated as they are added.	Non-namespace attributes
 * are not, as it would result in recursive calls before all the
 * namespace-related attribute objects are created.
 */
	private final void fillAllAttrs () {
		if (mAttrCount >= 0) {
			return;
		}
		mAttrCount = getXFAElement().getNumAttrs();
		for (int i = 0; i < mAttrCount; i++) {
			com.adobe.xfa.Attribute xfaAttr = getXFAElement().getAttr(i);
			AttrImpl newAttr = new AttrImpl (this, xfaAttr);
			if (newAttr.isNamespaceAttr (AttrImpl.CHECK_DEFAULT | AttrImpl.CHECK_PREFIX)) {
				newAttr.populate();
			}
			newAttr.setPrev (mLastAttr);
			if (mFirstAttr == null) {
				mFirstAttr = newAttr;
			} else {
				mLastAttr.setNext (newAttr);
			}
			mLastAttr = newAttr;
		}
	}

	@FindBugsSuppress(code="ES")
	private void addChildrenByTagName (String name, NodeListImpl nodeList) {
		if ((name == ALL_NODES) || (name == mQName.getQName())) {
			nodeList.addNode (this);
		}
		fillAllChildren();
		for (NodeImpl child = getFirstChildImpl(); child != null; child = child.getNext()) {
			if (child instanceof ElementImpl) {
				ElementImpl childElement = (ElementImpl) child;
				childElement.addChildrenByTagName (name, nodeList);
			}
		}
	}

	@FindBugsSuppress(code="ES")
	private void addChildrenByTagNameNS (String namespaceURI, String localName, NodeListImpl nodeList) {
		if ((namespaceURI == ALL_NODES) || (mQName.getNamespace() == namespaceURI)) {
			if ((localName == ALL_NODES) || (mQName.getLocalName() == localName)) {
				nodeList.addNode (this);
			}
		}
		fillAllChildren();
		for (NodeImpl child = getFirstChildImpl(); child != null; child = child.getNext()) {
			if (child instanceof ElementImpl) {
				ElementImpl childElement = (ElementImpl) child;
				childElement.addChildrenByTagNameNS (namespaceURI, localName, nodeList);
			}
		}
	}

	private void populateAttrMap () {
		if (mAttrMap != null) {
			return;
		}
		mAttrMap = new NamedNodeMapImpl (getXFAElement().getNumAttrs());
		fillAllAttrs();
		for (NodeImpl attr = mFirstAttr; attr != null; attr = attr.getNext()) {
			mAttrMap.addNode (attr);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy