DOM

This guide describes how to access a DOM document, find elements, modify a DOM structure, simulate user input, etc.

Overview

Each web page loaded in a Browser has a main Frame . The Frame itself may have child frames. For example, when a web page has IFRAMEs, please use the Frame class to access DOM and JavaScript.

Accessing document

Every Frame has a DOM Document. To access the Document please use the Frame.document() method:

frame.document().ifPresent(document -> {});
frame.document().ifPresent { document -> }

Finding elements

You can find HTML elements inside an element by different conditions. The following example demonstrates how to find all DIV elements inside the document element:

document.documentElement().ifPresent(documentElement ->
        documentElement.findElementsByTagName("div").forEach(element -> {})); 
document.documentElement().ifPresent { documentElement ->
        documentElement.findElementsByTagName("div").forEach { element -> } }

If you need to find only the first HTML element use the following approach:

documentElement.findElementByTagName("div").ifPresent(element -> {});
documentElement.findElementByTagName("div").ifPresent { element -> }

Here are the examples of searching for HTML elements by different conditions:

documentElement.findElementsById("<id>");
documentElement.findElementsByName("<attr-name>");
documentElement.findElementsByTagName("<tag-name>");
documentElement.findElementsByClassName("<attr-class>");
documentElement.findElementsById("<id>")
documentElement.findElementsByName("<attr-name>")
documentElement.findElementsByTagName("<tag-name>")
documentElement.findElementsByClassName("<attr-class>")

XPath

JxBrowser DOM API allows evaluating XPath expressions using Node.evaluate(String expression). You can evaluate an XPath expression in scope of a specified Node using the following code:

try {
    XPathResult result = node.evaluate("count(//div)");
} catch (XPathException e) {
    // Failed to evaluate the given expression.
}
try {
    val result: XPathResult = node.evaluate("count(//div)")
} catch (e: XPathException) {
    // Failed to evaluate the given expression.
}

The method throws XPathException when the library failed to evaluate the given expression.

The evaluation result is stored in the XPathResult object. Please make sure that the result contains the expected value type, e.g. Number, Boolean, String, Node, and extracts the value itself:

if (result.isNumber()) {
    double number = result.asNumber();
}
if (result.isNumber()) {
    val number: Double = result.asNumber()
}

Query selector

To find the elements that match a specified selector, e.g. #root, please use the following code:

List<Element> elements = element.findElementsByCssSelector("#root");
val elements = element.findElementsByCssSelector("#root")

Node at point

To find the Node at a specific point, e.g. 100x150, on the web page please use the following approach:

PointInspection inspection = frame.inspect(Point.of(100, 150));
inspection.node().ifPresent(node -> {});
val inspection: PointInspection = frame.inspect(Point.of(100, 150))
inspection.node().ifPresent { node -> }

Working with elements

Element bounds

You can get bounds of the Element with the position relative to the top-left of the viewport of the current Document as follows:

Rect rect = element.boundingClientRect();
val rect = element.boundingClientRect()

This method returns an empty Rect when the element has a hidden attribute or the CSS style of the element contains display: none; statement.

Element attributes

The Element class provides methods that allow you to get, add, remove, or modify the HTML element attributes. The following example demonstrates how to get all the attributes of the element and print their names and values:

element.attributes().forEach((name, value) ->
        System.out.println(name + ": " + value));
element.attributes().forEach { name, value ->
    println("$name: $value") 
}

The following example demonstrates how to add/modify an element attribute:

element.putAttribute("attrName", "attrValue");
element.putAttribute("attrName", "attrValue")

Creating elements

The DOM API allows modifying the document DOM structure. The following example demonstrates how to create and insert <p> element with some text:

// Create a new paragraph element.
Element paragraph = document.createElement("p");
// Create a text node with the given text.
Node text = document.createTextNode("Text");
// Insert the text node into the paragraph element.
if (paragraph.appendChild(text)) {
    // Insert the paragraph element into the required element.
    boolean success = element.appendChild(paragraph);
}
// Create a new paragraph element.
val paragraph = document.createElement("p")
// Create a text node with the given text.
val text = document.createTextNode("Text")
// Insert the text node into the paragraph element.
if (paragraph.appendChild(text)) {
    // Insert the paragraph element into the required element.
    success = element.appendChild(paragraph)
}

Closing nodes

DOM objects that have a Node counterpart are not subjects to Blink garbage collection. By default, we keep these objects in memory until the page is unloaded.

To optimize the memory usage, you can enable garbage collection on the per-object basis:

node.close();
node.close()

Closing Node marks the corresponding Blink object as collectable, but it does not release the object immediately. After calling the close() method, the attempts to use Node will lead to ObjectClosedException.

DOM events

Each Node implements the EventTarget interface that provides methods for registering DOM events. You can register DOM listener to receive DOM events such as click, mousedown, mouseup, keydown, load, error etc.

The following example demonstrates how to register a click event listener for a document HTML element:

document.documentElement().ifPresent(element ->
        element.addEventListener(EventType.CLICK, event -> {
            // Mouse click event has been received.
            if (event instanceof MouseEvent) {
                MouseEvent mouseEvent = (MouseEvent) event;
                int clickCount = mouseEvent.clickCount();
            }
        }, false));
document.documentElement().ifPresent { element ->
    element.addEventListener(EventType.CLICK, { event ->
            // Mouse click event has been received.
            if (event is MouseEvent) {
                val clickCount = event.clickCount()
            }
        }, false
    )
}

Also, JxBrowser allows you to listen to the custom DOM events and access their payload:

// Create a custom DOM event type.
EventType eventType = EventType.of("MyEvent");
// Listen to the events of the given event type.
element.addEventListener(eventType, event -> {
    // The MyEvent event has been received.
    if (event instanceof CustomEvent) {
        CustomEvent customEvent = (CustomEvent) event;
        JsObject payload = customEvent.detail();
    }
}, false);
// Create a custom DOM event type.
val eventType = EventType.of("MyEvent")
// Listen to the events of the given event type.
element.addEventListener(eventType, { event ->
    // The MyEvent event has been received.
    if (event is CustomEvent) {
        val payload = event.detail<JsObject>()
    }
}, false)

Automation

JxBrowser DOM API provides everything you need to automate the web form filling. This section describes how to update the text in the text fields, select a checkbox or a radio button, select one or multiple options in a drop-down list, simulate a click, etc.

To work with web form controls please use the FormControlElement interface. This interface allows to check whether the control is enabled, and to modify its value. All the form controls such as INPUT, SELECT, TEXTAREA, and others inherit this interface.

Input

To work with INPUT elements please use the InputElement interface. It provides all the required methods to check the input type and set its value.

Text, email, password

To replace the default value of a text, email, or password field with a new value, please use the InputElement.value(String) method.

For example, if your web form contains the <input> elements with the following types:

<input type="text" id="firstname" placeholder="First Name">
<input type="email" id="email" placeholder="Email Address">
<input type="password" id="password" placeholder="Password">

you can set their value using the following approach:

documentElement.findElementById("firstname").ifPresent(element ->
        ((InputElement) element).value("John"));

documentElement.findElementById("email").ifPresent(element ->
        ((InputElement) element).value("me@company.com"));

documentElement.findElementById("password").ifPresent(element ->
        ((InputElement) element).value("Jkdl12!"));
documentElement.findElementById("firstname").ifPresent { element ->
        (element as InputElement).value("John")
}

documentElement.findElementById("email").ifPresent { element ->
        (element as InputElement).value("me@company.com")
}

documentElement.findElementById("password").ifPresent { element ->
        (element as InputElement).value("Jkdl12!")
}

Check box, radio button

To check a radio button or a checkbox please use the InputElement.check() method.

For example, if your web form contains the <input> elements with the following types:

<input type="checkbox" id="checkbox" value="Remember me">
<input type="radio" id="radio" checked>

you can select/unselect them using the following approach:

documentElement.findElementById("checkbox").ifPresent(element ->
        ((InputElement) element).check());

documentElement.findElementById("radio").ifPresent(element ->
        ((InputElement) element).uncheck());
documentElement.findElementById("checkbox").ifPresent { element ->
        (element as InputElement).check()
}

documentElement.findElementById("radio").ifPresent { element ->
        (element as InputElement).uncheck()
}

File

The <input> elements with type=file let the user choose one or more files from their device storage. JxBrowser allows you to programmatically select a file and update the value of the <input type=file> elements.

For example, if your web form contains an <input> element like:

<input type="file" id="avatar" accept="image/png, image/jpeg" multiple>

you can select the required file/files programmatically using the following approach:

documentElement.findElementById("avatar").ifPresent(element ->
        ((InputElement) element).file("file1.png", "file2.jpeg"));
documentElement.findElementById("avatar").ifPresent { element ->
        (element as InputElement).file("file1.png", "file2.jpeg")
}

Text area

To set the text in a <textarea> element like:

<textarea id="details"></textarea>

please use the following approach:

documentElement.findElementById("details").ifPresent(element ->
        ((TextAreaElement) element).value("Some text..."));
documentElement.findElementById("details").ifPresent { element ->
        (element as TextAreaElement).value("Some text...")
}

Select & option

To select all options in a SELECT control like:

<select id="fruits" multiple>
    <option>Apple</option>
    <option>Orange</option>
    <option>Pineapple</option>
    <option>Banana</option>
</select>

please use the following approach:

documentElement.findElementById("fruits").ifPresent(element -> {
    SelectElement selectElement = (SelectElement) element;
    selectElement.options().forEach(optionElement ->
            optionElement.select());
});
documentElement.findElementById("fruits").ifPresent { element ->
        val selectElement = element as SelectElement
        selectElement.options().forEach { it.select() }
}

Using this approach you can select only one required option.

Simulating click

To simulate a mouse click on an element please use the following method:

element.click();
element.click()

When click() is used with the supported elements (such as an <input>), it fires the element’s click event. This event then bubbles up to the elements higher in the document tree and fires their click events.

Dispatching events

You can dispatch an Event at the specified EventTarget using the EventTarget.dispatch(Event) method.

The following example demonstrates how to dispatch a standard click event at the specified element:

// Client and screen location.
Point location = Point.of(10, 10);
// Create MouseEvent with the required options.
MouseEvent mouseClickEvent = document.createMouseEvent(EventType.CLICK,
        MouseEventParams.newBuilder()
                // The main button pressed.
                .button(Button.MAIN)
                .clientLocation(location)
                .screenLocation(location)
                .uiEventModifierParams(
                        UiEventModifierParams.newBuilder()
                                .eventParams(EventParams.newBuilder()
                                        .bubbles(true)
                                        .cancelable(true)
                                        .build())
                                .build())
                .build());
// Generate a click event on the target element.
element.dispatch(mouseClickEvent);
// Client and screen location.
val location = Point.of(10, 10)
// Create MouseEvent with the required options.
val mouseClickEvent = document.createMouseEvent(EventType.CLICK,
        MouseEventParams.newBuilder()
                // The main button pressed.
                .button(Button.MAIN)
                .clientLocation(location)
                .screenLocation(location)
                .uiEventModifierParams(
                        UiEventModifierParams.newBuilder()
                                .eventParams(EventParams.newBuilder()
                                        .bubbles(true)
                                        .cancelable(true)
                                        .build())
                                .build())
                .build())
// Generate a click event on the target element.
element.dispatch(mouseClickEvent)

Using this approach you can create and dispatch various DOM events. Such events are commonly called synthetic events , as opposed to the events fired by the Browser itself.

Go Top