/** * Loads an XML document using the supplied string. * * @param strXML A string containing the XML string to load into this XML document object This * string can contain an entire XML document or a well-formed fragment. * @return true if the load succeeded; false if the load failed */ public boolean jsxFunction_loadXML(final String strXML) { try { final WebWindow webWindow = getWindow().getWebWindow(); // determine the charset of the page String charset = TextUtil.DEFAULT_CHARSET; final SgmlPage sgmlPage = (SgmlPage) webWindow.getEnclosedPage(); if (sgmlPage != null) { final String contentCharset = sgmlPage.getWebResponse().getContentCharset(); if (contentCharset != null) { charset = contentCharset; } } // build a dummy WebResponse List<NameValuePair> headers = Collections.emptyList(); final WebResponseData data = new WebResponseData( TextUtil.stringToByteArray(strXML, charset), HttpStatus.SC_OK, null, headers); final URL hackUrl = new URL("http://-htmlunit-internal/XMLDocument.loadXML"); // hack! better solution? final WebResponse webResponse = new WebResponse(data, hackUrl, (HttpMethod) null, 0); webResponse.getWebRequest().setCharset(charset); final XmlPage page = new XmlPage(webResponse, webWindow); setDomNode(page); return true; } catch (final IOException e) { if (LOG.isDebugEnabled()) { LOG.debug("Error parsing XML\n" + strXML, e); } return false; } }
/** * Indicates if script execution is necessary and/or possible. * * @return <code>true</code> if the script should be executed */ private boolean isExecutionNeeded() { final SgmlPage page = getPage(); if (!isDirectlyAttachedToPage()) { return false; } // If JavaScript is disabled, we don't need to execute. if (!page.getWebClient().isJavaScriptEnabled()) { return false; } // If innerHTML or outerHTML is being parsed if (page instanceof HtmlPage && ((HtmlPage) page).isParsingHtmlSnippet()) { return false; } // If the script node is nested in an iframe, a noframes, or a noscript node, we don't need to // execute. for (DomNode o = this; o != null; o = o.getParentNode()) { if (o instanceof HtmlInlineFrame || o instanceof HtmlNoFrames) { return false; } } // If the underlying page no longer owns its window, the client has moved on (possibly // because another script set window.location.href), and we don't need to execute. if (page.getEnclosingWindow() != null && page.getEnclosingWindow().getEnclosedPage() != page) { return false; } // If the script language is not JavaScript, we can't execute. if (!isJavaScript(getTypeAttribute(), getLanguageAttribute())) { final String t = getTypeAttribute(); final String l = getLanguageAttribute(); LOG.warn( "Script is not JavaScript (type: " + t + ", language: " + l + "). Skipping execution."); return false; } // If the script's root ancestor node is not the page, the the script is not a part of the page. // If it isn't yet part of the page, don't execute the script; it's probably just being cloned. DomNode root = this; while (root.getParentNode() != null) { root = root.getParentNode(); } if (root != getPage()) { return false; } return true; }
/** * Applies the specified XPath expression to this node's context and returns the generated list of * matching nodes. * * @param expression a string specifying an XPath expression * @return list of the found elements */ public HTMLCollection jsxFunction_selectNodes(final String expression) { final boolean attributeChangeSensitive = expression.contains("@"); final String description = "XMLDocument.selectNodes('" + expression + "')"; final SgmlPage page = getPage(); final HTMLCollection collection = new HTMLCollection(page.getDocumentElement(), attributeChangeSensitive, description) { protected List<Object> computeElements() { final List<Object> list = new ArrayList<Object>(page.getByXPath(expression)); return list; }; }; return collection; }
/** * Creates an instance. * * @param namespaceURI the URI that identifies an XML namespace * @param qualifiedName the qualified name of the element type to instantiate * @param page the page that contains this element * @param attributes the initial attributes */ HtmlFileInput( final String namespaceURI, final String qualifiedName, final SgmlPage page, final Map<String, DomAttr> attributes) { super(namespaceURI, qualifiedName, page, attributes); setAttribute("value", ""); if (page.getWebClient() .getBrowserVersion() .hasFeature(BrowserVersionFeatures.FILEINPUT_EMPTY_DEFAULT_VALUE)) { setDefaultValue(""); } }
/** * Sets a value which indicates whether or not the document can be edited. * * @param mode a value which indicates whether or not the document can be edited */ @JsxSetter public void setDesignMode(final String mode) { final boolean inherit = getBrowserVersion().hasFeature(JS_DOCUMENT_DESIGN_MODE_INHERIT); if (inherit) { if (!"on".equalsIgnoreCase(mode) && !"off".equalsIgnoreCase(mode) && !"inherit".equalsIgnoreCase(mode)) { throw Context.reportRuntimeError("Invalid document.designMode value '" + mode + "'."); } if (!(getWindow().getWebWindow() instanceof FrameWindow) && getBrowserVersion().hasFeature(JS_DOCUMENT_DESIGN_MODE_ONLY_FOR_FRAMES)) { // IE evaluates all designMode changes for documents that aren't in frames as Off designMode_ = "off"; } else if ("on".equalsIgnoreCase(mode)) { designMode_ = "on"; } else if ("off".equalsIgnoreCase(mode)) { designMode_ = "off"; } else if ("inherit".equalsIgnoreCase(mode)) { designMode_ = "inherit"; } if (getBrowserVersion().hasFeature(JS_DOCUMENT_DESIGN_MODE_CAPITAL_FIRST)) { designMode_ = StringUtils.capitalize(designMode_); } } else { if ("on".equalsIgnoreCase(mode)) { designMode_ = "on"; final SgmlPage page = getPage(); if (page != null && page.isHtmlPage()) { final HtmlPage htmlPage = (HtmlPage) page; final DomNode child = htmlPage.getBody().getFirstChild(); final DomNode rangeNode = child == null ? htmlPage.getBody() : child; htmlPage.setSelectionRange(new SimpleRange(rangeNode, 0)); } } else if ("off".equalsIgnoreCase(mode)) { designMode_ = "off"; } } }
/** * Add missing attribute if needed by fixing attribute map rather to add it afterwards as this * second option triggers the instantiation of the script object at a time where the DOM node has * not yet been added to its parent. */ private static Map<String, DomAttr> addValueIfNeeded( final SgmlPage page, final Map<String, DomAttr> attributes) { final BrowserVersion browserVersion = page.getWebClient().getBrowserVersion(); if (browserVersion.hasFeature(RESETINPUT_DEFAULT_VALUE_IF_VALUE_NOT_DEFINED)) { for (final String key : attributes.keySet()) { if ("value".equalsIgnoreCase(key)) { return attributes; // value attribute was specified } } // value attribute was not specified, add it final DomAttr newAttr = new DomAttr(page, null, "value", DEFAULT_VALUE, true); attributes.put("value", newAttr); } return attributes; }
/** * Create a new HTML element with the given tag name. * * @param tagName the tag name * @return the new HTML element, or NOT_FOUND if the tag is not supported */ @JsxFunction public Object createElement(String tagName) { Object result = NOT_FOUND; try { final BrowserVersion browserVersion = getBrowserVersion(); // FF3.6 supports document.createElement('div') or supports document.createElement('<div>') // but not document.createElement('<div name="test">') // IE9- supports also document.createElement('<div name="test">') // FF4+ and IE11 don't support document.createElement('<div>') if (browserVersion.hasFeature(BrowserVersionFeatures.JS_DOCUMENT_CREATE_ELEMENT_STRICT) && (tagName.contains("<") || tagName.contains(">"))) { LOG.info( "createElement: Provided string '" + tagName + "' contains an invalid character; '<' and '>' are not allowed"); throw Context.reportRuntimeError("String contains an invalid character"); } else if (!browserVersion.hasFeature(JS_DOCUMENT_CREATE_ELEMENT_EXTENDED_SYNTAX) && tagName.startsWith("<") && tagName.endsWith(">")) { tagName = tagName.substring(1, tagName.length() - 1); final Matcher matcher = TAG_NAME_PATTERN.matcher(tagName); if (!matcher.matches()) { LOG.info( "createElement: Provided string '" + tagName + "' contains an invalid character"); throw Context.reportRuntimeError("String contains an invalid character"); } } final SgmlPage page = getPage(); final org.w3c.dom.Node element; if ("comment".equalsIgnoreCase(tagName) && browserVersion.hasFeature(JS_DOCUMENT_CREATE_ELEMENT_COMMENT)) { element = new DomComment(page, ""); } else { element = page.createElement(tagName); if (element instanceof BaseFrameElement) { ((BaseFrameElement) element).markAsCreatedByJavascript(); } else if (element instanceof HtmlInput) { ((HtmlInput) element).markAsCreatedByJavascript(); } else if (element instanceof HtmlImage) { ((HtmlImage) element).markAsCreatedByJavascript(); } else if (element instanceof HtmlKeygen) { ((HtmlKeygen) element).markAsCreatedByJavascript(); } else if (element instanceof HtmlRp) { ((HtmlRp) element).markAsCreatedByJavascript(); } else if (element instanceof HtmlRt) { ((HtmlRt) element).markAsCreatedByJavascript(); } else if (element instanceof HtmlUnknownElement) { ((HtmlUnknownElement) element).markAsCreatedByJavascript(); } } final Object jsElement; if ("event".equalsIgnoreCase(tagName) && browserVersion.hasFeature(JS_DOCUMENT_CREATE_ELEMENT_COMMENT)) { jsElement = new SimpleScriptable(); ((SimpleScriptable) jsElement).setClassName("Object"); ((SimpleScriptable) jsElement).setParentScope(window_); } else { jsElement = getScriptableFor(element); } if (jsElement == NOT_FOUND) { if (LOG.isDebugEnabled()) { LOG.debug( "createElement(" + tagName + ") cannot return a result as there isn't a JavaScript object for the element " + element.getClass().getName()); } } else { result = jsElement; } } catch (final ElementNotFoundException e) { // Just fall through - result is already set to NOT_FOUND } return result; }