Class DomContainer

java.lang.Object
com.machinezoo.pushmode.dom.DomContent
com.machinezoo.pushmode.dom.DomContainer
All Implemented Interfaces:
Cloneable
Direct Known Subclasses:
DomElement, DomFragment

@NoTests public abstract class DomContainer extends DomContent
Base class for DomElement and DomFragment. This class provides methods common to both, which mostly includes nearly all methods for modifying and querying the list of child nodes (child elements and text).

Since DomFragment is nothing more than a list of child nodes, DomFragment is implemented as a thin wrapper around DomContainer.

Children are of type DomContent. They are either DomElement or DomText. When DomFragment is added to another fragment or to an element, it is inlined. Fragments cannot be children of elements or other fragments. There are never two consecutive DomText nodes in the child list. If text is appended to a child list that already ends with text node, a new DomText node is created in its place that contains both strings concatenated together.

Due to this non-trivial manipulation of appended content, it doesn't make much sense to provide list-like functionality (set, insert, or remove children) and the whole child manipulation API is append-only. It fits the typical functional programming use case of building DOM trees from scratch. If DOM tree modification is needed, for example to expand templates, apply DOM tree filters, or to import external content, the best approach is to build new DOM tree with desired changes applied and discard the original DOM tree. The only mutating method we support is children().clear(), so that contents of this DomContainer can be replaced without replacing the whole object.

Since using the high-level builder and query API might be too much overhead in some cases, a low-level raw access API is provided too. It is application's responsibility to use the raw API correctly.

  • Method Details

    • rawChildCount

      @DraftApi public int rawChildCount()
      Gets number of child nodes. This is a raw API equivalent to calling children().size().
      Returns:
      number of child nodes
      See Also:
    • rawChildren

      @DraftApi public DomContent[] rawChildren()
      Gets child node buffer. This is a raw API returning essentially the same information as children().

      The buffer may be larger than the number of child nodes actually present. Extra entries are filled with nulls. If there are no children, the buffer may be null.

      The returned array may be modified, but application should satisfy the same requirements as with rawChildren(int, DomContent[]).

      Returns:
      null-padded array of child nodes or null
      See Also:
    • rawChildren

      @DraftApi public void rawChildren(int count, DomContent[] children)
      Sets child node buffer. This is a raw API to be used under extreme circumstances. The proper high-level way to fill child node buffer is to use the many add() methods. If child list has to be modified, the high-level way to do it is to rebuild the whole element/fragment.

      The new child buffer must satisfy several requirements. It can only contain DomElement and DomText instances and there must be no consecutive text nodes and no null nodes. If count is smaller than the size of the buffer, unused entries at the end of the buffer must be null. The buffer itself may be null if count is zero. These requirements are not checked. If application fails to satisfy them, it may result in surprising behavior or exceptions.

      This method does no check whether the container is frozen. This is application's responsibility. Modifying frozen containers is unsafe.

      Parameters:
      count - new child count
      children - new child node buffer or null
      See Also:
    • add

      public DomContainer add(DomContent child)
      Adds new child node to the list of children. Fragments will be inlined, nulls ignored, and text concatenated.
      Parameters:
      child - node to add (ignored if null)
      Returns:
      this
      Throws:
      IllegalStateException - if this element or fragment is frozen
      See Also:
    • add

      public <C extends DomContent> DomContainer add(Collection<C> children)
      Adds all nodes in a Collection to the list of children. Fragments will be inlined, nulls ignored, and text concatenated.
      Type Parameters:
      C - item type
      Parameters:
      children - collection of child nodes to add (ignored if null)
      Returns:
      this
      Throws:
      IllegalStateException - if this element or fragment is frozen
      See Also:
    • add

      public <C extends DomContent> DomContainer add(Stream<C> children)
      Adds all nodes in a Stream to the list of children. Fragments will be inlined, nulls ignored, and text concatenated.
      Type Parameters:
      C - item type
      Parameters:
      children - Stream of child nodes to add (ignored if null)
      Returns:
      this
      Throws:
      IllegalStateException - if this element or fragment is frozen
      See Also:
    • add

      public DomContainer add(String text)
      Adds literal text to the list of children. Consecutive text nodes will be concatenated.
      Parameters:
      text - text to add (ignored if null or empty)
      Returns:
      this
      Throws:
      IllegalStateException - if this element or fragment is frozen
      See Also:
    • children

      @DraftCode("sublists are copies instead of views") public List<DomContent> children()
      Lists all children in this element or fragment. The list is a live view of the internal representation of the child list. It will reflect changes made through other methods of this class. The returned list itself is unmodifiable except for List.clear().

      All methods of the returned List have time complexity like methods of ArrayList except List.subList(int, int), which is currently implemented as returning copy of the sublist rather than a view.

      Returns:
      list of all children
      See Also:
    • elements

      public Stream<DomElement> elements()
      Enumerates element children. This is a convenience filter applied to children().
      Returns:
      stream of children of type DomElement
      See Also:
    • descendants

      public Stream<DomElement> descendants()
      Enumerates descendant elements. Elements are traversed in pre-order depth-first manner. The returned stream is constructed incrementally as it is consumed. DomElement provides method DomElement.descendantsAndSelf().
      Returns:
      stream of descendant elements
      See Also:
    • elements

      public Stream<DomElement> elements(String name)
      Enumerates elements with given tagname. This is a convenience filter applied to children().
      Parameters:
      name - tagname to look for
      Returns:
      stream of elements with the tagname
      See Also:
    • element

      public Optional<DomElement> element(String name)
      Finds element with given tagname. This is a convenience filter applied to children().
      Parameters:
      name - tagname to look for
      Returns:
      element with the tagname or an empty Optional
      See Also:
    • text

      @DraftApi("see base class") public String text()
      Description copied from class: DomContent
      Gets concatenated text content of this node. Text is concatenated recursively in the same order in which it would appear in HTML. Attribute values are not included. No whitespace normalization is performed.
      Specified by:
      text in class DomContent
      Returns:
      all text content in this node
    • rawFreeze

      @DraftApi public void rawFreeze()
      Marks the element or fragment as frozen. This is a raw API that merely marks the container as frozen without performing any other tasks like freeze().
    • freeze

      public DomContainer freeze()
      Protects this element or fragment from further modification. For more information, use cases, and thread safety, see DomContent.freeze().
      Specified by:
      freeze in class DomContent
      Returns:
      this
    • clone

      public abstract DomContainer clone()
      Creates mutable deep clone of this element or fragment. All child nodes are cloned recursively. The clone is completely independent of this node.
      Specified by:
      clone in class DomContent
      Returns:
      deep mutable clone
    • equals

      public boolean equals(Object object)
      Compares content of two DomContainer nodes. If the two nodes are of different type (i.e. one is DomElement and the other one DomFragment), this method returns false. Equality is unaffected by whether the element/fragment is frozen or not. Children of both containers are compared recursively by calling their DomContent.equals(Object) methods.
      Overrides:
      equals in class DomContent
      Parameters:
      object - object to compare this container with
      Returns:
      true if the two nodes are equal, false otherwise
    • hashCode

      public int hashCode()
      Computes hash code of this container. It is computed by combining hash codes of all children. Hash code is unaffected by whether the element/fragment is frozen or not.
      Overrides:
      hashCode in class DomContent
      Returns:
      container's hash code