Пример #1
0
  /**
   * 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;
    }
  }
Пример #2
0
  /**
   * 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;
  }
Пример #3
0
 /**
  * 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;
 }
Пример #4
0
 /**
  * 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("");
   }
 }
Пример #5
0
  /**
   * 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";
      }
    }
  }
Пример #6
0
  /**
   * 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;
  }
Пример #7
0
  /**
   * 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;
  }