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

com.gargoylesoftware.htmlunit.activex.javascript.msxml.XMLDOMElement Maven / Gradle / Ivy

There is a newer version: 2.70.0
Show newest version
/*
 * Copyright (c) 2002-2018 Gargoyle Software Inc.
 *
 * 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 com.gargoylesoftware.htmlunit.activex.javascript.msxml;

import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.IE;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;

import com.gargoylesoftware.htmlunit.html.DomAttr;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.DomNode;
import com.gargoylesoftware.htmlunit.html.DomText;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxClass;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxFunction;
import com.gargoylesoftware.htmlunit.javascript.configuration.JsxGetter;
import com.gargoylesoftware.htmlunit.javascript.host.dom.Node;

import net.sourceforge.htmlunit.corejs.javascript.Context;

/**
 * A JavaScript object for MSXML's (ActiveX) XMLDOMElement.
* Represents the element object. * @see MSDN documentation * * @author Ahmed Ashour * @author Marc Guillemot * @author Sudhan Moghe * @author Ronald Brill * @author Frank Danek */ @JsxClass(domClass = DomElement.class, value = IE) public class XMLDOMElement extends XMLDOMNode { private XMLDOMNamedNodeMap attributes_; private Map elementsByTagName_; // for performance and for equality (==) /** * Returns the list of attributes for this element. * @return the list of attributes for this element */ @Override public Object getAttributes() { if (attributes_ == null) { attributes_ = createAttributesObject(); } return attributes_; } /** * Creates the JS object for the property attributes. This object will the be cached. * @return the JS object */ protected XMLDOMNamedNodeMap createAttributesObject() { return new XMLDOMNamedNodeMap(getDomNodeOrDie()); } /** * Attempting to set the value of elements generates an error. * @param newValue the new value to set */ @Override public void setNodeValue(final String newValue) { if (newValue == null || "null".equals(newValue)) { throw Context.reportRuntimeError("Type mismatch."); } throw Context.reportRuntimeError("This operation cannot be performed with a node of type ELEMENT."); } /** * Returns the element name. * @return the element name */ @JsxGetter public String getTagName() { return getNodeName(); } /** * Returns a string that represents the element content. This will also include the text content from all child * elements, concatenated in document order. * @return a string that represents the element content */ @Override public String getText() { final StringBuilder builder = new StringBuilder(); toText(getDomNodeOrDie(), builder); if (builder.length() > 0 && builder.charAt(builder.length() - 1) == '\n') { return builder.substring(0, builder.length() - 1); } return builder.toString(); } /** * Replaces all children of this element with the supplied value. * @param value the new value for the contents of this node */ @Override public void setText(final Object value) { if (value == null || "null".equals(value)) { throw Context.reportRuntimeError("Type mismatch."); } super.setText(value); } private void toText(final DomNode node, final StringBuilder builder) { switch (node.getNodeType()) { case Node.DOCUMENT_TYPE_NODE: case Node.NOTATION_NODE: return; case Node.TEXT_NODE: case Node.CDATA_SECTION_NODE: case Node.COMMENT_NODE: case Node.PROCESSING_INSTRUCTION_NODE: builder.append(node.getNodeValue()); break; default: } boolean lastWasElement = false; for (final DomNode child : node.getChildren()) { switch (child.getNodeType()) { case Node.ELEMENT_NODE: lastWasElement = true; toText(child, builder); break; case Node.TEXT_NODE: case Node.CDATA_SECTION_NODE: if (StringUtils.isBlank(child.getNodeValue())) { if (lastWasElement) { builder.append(' '); } lastWasElement = false; break; } lastWasElement = false; builder.append(child.getNodeValue()); break; default: lastWasElement = false; } } } /** * Returns the value of the attribute. * @param name the name of the attribute to return * @return the value of the specified attribute, {@code null} if the named attribute does not have a * specified value */ @JsxFunction public Object getAttribute(final String name) { if (name == null || "null".equals(name)) { throw Context.reportRuntimeError("Type mismatch."); } if (StringUtils.isEmpty(name)) { throw Context.reportRuntimeError("The empty string '' is not a valid name."); } final String value = getDomNodeOrDie().getAttribute(name); if (value == DomElement.ATTRIBUTE_NOT_DEFINED) { return null; } return value; } /** * Returns the attribute node. * @param name the name of the attribute to return * @return the attribute node with the supplied name, {@code null} if the named attribute cannot be found * on this element */ @JsxFunction public Object getAttributeNode(final String name) { if (name == null || "null".equals(name)) { throw Context.reportRuntimeError("Type mismatch."); } if (StringUtils.isEmpty(name)) { throw Context.reportRuntimeError("The empty string '' is not a valid name."); } final Map attributes = getDomNodeOrDie().getAttributesMap(); for (final DomAttr attr : attributes.values()) { if (attr.getName().equals(name)) { return attr.getScriptableObject(); } } return null; } /** * Removes the named attribute. * @param name the name of the attribute to be removed */ @JsxFunction public void removeAttribute(final String name) { if (name == null || "null".equals(name)) { throw Context.reportRuntimeError("Type mismatch."); } if (StringUtils.isEmpty(name)) { throw Context.reportRuntimeError("The empty string '' is not a valid name."); } getDomNodeOrDie().removeAttribute(name); delete(name); } /** * Removes the specified attribute from this element. * @param att the attribute to be removed from this element * @return the removed attribute */ @JsxFunction public XMLDOMAttribute removeAttributeNode(final XMLDOMAttribute att) { if (att == null) { throw Context.reportRuntimeError("Type mismatch."); } final String name = att.getName(); final XMLDOMNamedNodeMap nodes = (XMLDOMNamedNodeMap) getAttributes(); final XMLDOMAttribute removedAtt = (XMLDOMAttribute) nodes.getNamedItemWithoutSyntheticClassAttr(name); if (removedAtt != null) { removedAtt.detachFromParent(); } removeAttribute(name); return removedAtt; } /** * Sets the value of the named attribute. * * @param name the name of the attribute; if the attribute with that name already exists, its value is changed * @param value the value for the named attribute */ @JsxFunction public void setAttribute(final String name, final String value) { if (name == null || "null".equals(name)) { throw Context.reportRuntimeError("Type mismatch."); } if (StringUtils.isEmpty(name)) { throw Context.reportRuntimeError("The empty string '' is not a valid name."); } if (value == null || "null".equals(value)) { throw Context.reportRuntimeError("Type mismatch."); } getDomNodeOrDie().setAttribute(name, value); } /** * Sets or updates the supplied attribute node on this element. * @param newAtt the attribute node to be associated with this element * @return the replaced attribute node, if any, {@code null} otherwise */ @JsxFunction public XMLDOMAttribute setAttributeNode(final XMLDOMAttribute newAtt) { if (newAtt == null) { throw Context.reportRuntimeError("Type mismatch."); } final String name = newAtt.getBaseName(); final XMLDOMNamedNodeMap nodes = (XMLDOMNamedNodeMap) getAttributes(); final XMLDOMAttribute replacedAtt = (XMLDOMAttribute) nodes.getNamedItemWithoutSyntheticClassAttr(name); if (replacedAtt != null) { replacedAtt.detachFromParent(); } final DomAttr newDomAttr = newAtt.getDomNodeOrDie(); getDomNodeOrDie().setAttributeNode(newDomAttr); return replacedAtt; } /** * Returns a list of all descendant elements that match the supplied name. * @param tagName the name of the element to find; the tagName value '*' matches all descendant elements of this * element * @return a list containing all elements that match the supplied name */ @JsxFunction public XMLDOMNodeList getElementsByTagName(final String tagName) { if (tagName == null || "null".equals(tagName)) { throw Context.reportRuntimeError("Type mismatch."); } final String tagNameTrimmed = tagName.trim(); if (elementsByTagName_ == null) { elementsByTagName_ = new HashMap<>(); } XMLDOMNodeList collection = elementsByTagName_.get(tagNameTrimmed); if (collection != null) { return collection; } final DomNode node = getDomNodeOrDie(); final String description = "XMLDOMElement.getElementsByTagName('" + tagNameTrimmed + "')"; if ("*".equals(tagNameTrimmed)) { collection = new XMLDOMNodeList(node, false, description) { @Override protected boolean isMatching(final DomNode domNode) { return true; } }; } else if ("".equals(tagNameTrimmed)) { collection = new XMLDOMNodeList(node, false, description) { @Override protected List computeElements() { final List response = new ArrayList<>(); final DomNode domNode = getDomNodeOrNull(); if (domNode == null) { return response; } for (final DomNode candidate : getCandidates()) { if (candidate instanceof DomText) { final DomText domText = (DomText) candidate; if (!StringUtils.isBlank(domText.getWholeText())) { response.add(candidate); } } else { response.add(candidate); } } return response; } }; } else { collection = new XMLDOMNodeList(node, false, description) { @Override protected boolean isMatching(final DomNode domNode) { return tagNameTrimmed.equals(domNode.getNodeName()); } }; } elementsByTagName_.put(tagName, collection); return collection; } /** * Normalizes all descendant elements by combining two or more adjacent text nodes into one unified text node. */ @JsxFunction public void normalize() { final DomElement domElement = getDomNodeOrDie(); domElement.normalize(); // normalize all descendants normalize(domElement); } private void normalize(final DomElement domElement) { for (DomNode domNode : domElement.getChildren()) { if (domNode instanceof DomElement) { domNode.normalize(); normalize((DomElement) domNode); } } } /** * {@inheritDoc} */ @Override public DomElement getDomNodeOrDie() { return (DomElement) super.getDomNodeOrDie(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy