package textbender.g.xml.dom; // Copyright 2006-2007, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Textbender Software"), to deal in the Textbender Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Textbender Software, and to permit persons to whom the Textbender Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Textbender Software. THE TEXTBENDER SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE TEXTBENDER SOFTWARE OR THE USE OR OTHER DEALINGS IN THE TEXTBENDER SOFTWARE. import org.w3c.dom.*; import textbender.g.lang.*; /** Node utilities. */ public final class NodeX { private NodeX() {} /** Returns the named processing instruction, if one exists as a child of the parent node. * * @param parent to search * @param target name of processing instruction * * @return named processing instruction, * or null if none exists as a child of the parent node */ public static ProcessingInstruction findChildProcessingInstruction( Node parent, String target ) { NodeList childList = parent.getChildNodes(); for( int c = 0, cN = childList.getLength(); c < cN; ++c ) // OPT iterate by Node.getNextSibling() { Node child = childList.item( c ); if( !( child instanceof ProcessingInstruction )) continue; ProcessingInstruction iP = (ProcessingInstruction)child; if( iP.getTarget().equals( target )) return iP; } return null; } /** Answers whether one node (a) is an ancestor of another (d); * or equivalently whether d is a descendant of a. * * @return true iff a has descendant d */ public static boolean areAncestorAndDescendant( Node a, Node d ) { if( a == null || d == null ) return false; for( ;; ) { d = d.getParentNode(); if( d == null ) return false; if( a.isSameNode( d )) return true; } } /** Returns the index of the specified child in the parent node. * * @return index, or -1 if parent has no such child */ public static int indexIn( final Node parent, final Node child ) { int s = 0; for( Node sib = parent.getFirstChild(); sib != null; sib = sib.getNextSibling(), ++s ) { if( sib.isSameNode( child )) return s; } return -1; } /** Removes from 'fromParent' all child elements of the specified name, * and appends them to 'toParent'. */ public static void moveElementsNS( final Node fromParent, final String namespaceURI, final String localName, final Node toParent ) { Node child; for( Node c = fromParent.getFirstChild(); c != null; ) { child = c; c = c.getNextSibling(); if( child instanceof Element ) { if( localName.equals( child.getLocalName() ) && ObjectX.nullEquals( namespaceURI, child.getNamespaceURI() )) { toParent.appendChild( child ); } } } } /** Returns the next node, in document order. * Equivalent to {@linkplain #nextNode(Node,boolean) nextNode(node,true)} * and org.w3c.dom.traversal.TreeWalker.nextNode(). * * @param node reference node, which may be null * * @return next node; or null if reference node is null, * or document has no more nodes */ public static Node nextNode( Node node ) { return nextNode( node, /*deeply*/true ); } /** Returns the next node, in document order. * nextNode(node,true) is equivalent * to org.w3c.dom.traversal.TreeWalker.nextNode(). * * @param node reference node, which may be null * @param deeply if true, return the first child node (if any) * * @return next node; or null if reference node is null, * or document has no more nodes */ public static Node nextNode( final Node node, final boolean deeply ) { Node nextNode = null; // till proven otherwise walk: if( node != null ) { if( deeply ) { nextNode = node.getFirstChild(); if( nextNode != null ) break walk; } nextNode = node.getNextSibling(); if( nextNode != null ) break walk; nextNode = nextNode( node.getParentNode(), /*deeply*/false ); } return nextNode; } /** Returns true iff the nodes are either the 'same nodes', or both null. */ public static boolean nullSame( Node n1, Node n2 ) { if( n1 == null || n2 == null ) return n1 == n2; else return n1.isSameNode( n2 ); } // ` T e s t `````````````````````````````````````````````````````````````````````````` /** Test code. */ public static void _testWalk( final Node node ) { System.err.println( "_testWalk: " + node ); for( Node child = node.getFirstChild(); child != null; child = child.getNextSibling() ) { _testWalk( child ); } } }