package Java; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.Text; import static org.w3c.dom.Node.ELEMENT_NODE; import static org.w3c.dom.Node.TEXT_NODE; /** @see org.w3c.dom.Node */ public final class Nodes { private Nodes() {} /** Whether `name` is the local name of `node`. * * @throws NullPointerException If either `name` or `node` is null. */ public static boolean hasName( final String name, final Node node ) { return name.equals( node.getLocalName() ); } /** Whether `node` is typed an an element. * * @see Node#getNodeType() * @throws NullPointerException If `node` is null. Note the difference from the behaviour * of the `instanceof` operator, which would instead return true. */ public static boolean isElement( final Node node ) { return node.getNodeType() == ELEMENT_NODE; } /** Whether `node` is typed as text. * * @see Node#getNodeType() * @throws NullPointerException If `node` is null. Note the difference from the behaviour * of the `instanceof` operator, which would instead return true. */ public static boolean isText( final Node node ) { return node.getNodeType() == TEXT_NODE; } /** Returns the nearest of the node’s subsequent siblings of the given local name, * or null if there are none. */ public static Node nextSibling( Node node, final String name ) { do node = node.getNextSibling(); while( node != null && !hasName( name, node )); return node; } /** Returns the parent of `node` as an element, or null if `node` has no parent. * * @throws ClassCastException If the parent of `node` is neither null nor an element. */ public static Element parentAsElement( final Node node ) { return (Element)node.getParentNode(); } /** Returns the parent of `node` as an element; or null if `node` either has no parent, * or its parent is not an element. */ public static Element parentElement( Node node ) { node = node.getParentNode(); return node instanceof Element ? (Element)node : null; } /** Returns the nearest of the node’s prior siblings of the given local name, * or null if there are none. */ public static Node previousSibling( Node node, final String name ) { do node = node.getPreviousSibling(); while( node != null && !hasName( name, node )); return node; } /** Returns the successor of `node` in document order, including any first child, * or null if `node` has no successor. * * @see * Definition of ‘document order’ */ public static Node successor( final Node node ) { Node s = node.getFirstChild(); if( s == null ) s = successorAfter( node ); return s; } /** Returns the exclusive successor of `node` in document order, or null if there is none. * * @see * Definition of ‘document order’ * @return The first successor of `node` outside of its descendants, or null if none exists. */ public static Node successorAfter( final Node node ) { Node s = node.getNextSibling(); if( s == null ) { final Node p = node.getParentNode(); if( p != null ) s = successorAfter( p ); } return s; } /** Returns the elemental successor of `n` in document order, including any first child, * or null if `n` has no elemental successor. * * @see * Definition of ‘document order’ */ public static Element successorElement( Node n ) { do n = successor( n ); while( n != null && !isElement(n) ); return (Element)n; } /** Returns the exclusive elemental successor of `n` in document order, or null if there is none. * * @see * Definition of ‘document order’ * @return The first elemental successor of `n` outside of its descendants, * or null if none exists. */ public static Element successorElementAfter( Node n ) { do n = successorAfter( n ); while( n != null && !isElement(n) ); return (Element)n; } /** Returns the flat text (aka `data`) of the first child of the given node, * which child must be a text node. */ public static String textChildFlat( final Node n ) { return ((Text)n.getFirstChild()).getData(); }} // Copyright © 2022 Michael Allan. Licence MIT.