Clover coverage report - Clover results for XOM 1.2d1
Coverage timestamp: Wed Feb 8 2006 08:31:33 EST
file stats: LOC: 810   Methods: 28
NCLOC: 442   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DOMConverter.java 89.5% 92.8% 92.9% 91.9%
coverage coverage
 1    /* Copyright 2002-2006 Elliotte Rusty Harold
 2   
 3    This library is free software; you can redistribute it and/or modify
 4    it under the terms of version 2.1 of the GNU Lesser General Public
 5    License as published by the Free Software Foundation.
 6   
 7    This library is distributed in the hope that it will be useful,
 8    but WITHOUT ANY WARRANTY; without even the implied warranty of
 9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 10    GNU Lesser General Public License for more details.
 11   
 12    You should have received a copy of the GNU Lesser General Public
 13    License along with this library; if not, write to the
 14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 15    Boston, MA 02111-1307 USA
 16   
 17    You can contact Elliotte Rusty Harold by sending e-mail to
 18    elharo@metalab.unc.edu. Please include the word "XOM" in the
 19    subject line. The XOM home page is located at http://www.xom.nu/
 20    */
 21   
 22    package nu.xom.converters;
 23   
 24    import nu.xom.Attribute;
 25    import nu.xom.Comment;
 26    import nu.xom.DocType;
 27    import nu.xom.Document;
 28    import nu.xom.Element;
 29    import nu.xom.Node;
 30    import nu.xom.NodeFactory;
 31    import nu.xom.Nodes;
 32    import nu.xom.ParentNode;
 33    import nu.xom.ProcessingInstruction;
 34    import nu.xom.Text;
 35    import nu.xom.XMLException;
 36   
 37    import org.w3c.dom.Attr;
 38    import org.w3c.dom.DOMImplementation;
 39    import org.w3c.dom.DocumentFragment;
 40    import org.w3c.dom.DocumentType;
 41    import org.w3c.dom.NamedNodeMap;
 42    import org.w3c.dom.NodeList;
 43    // Many DOM interfaces such as Element and Document
 44    // have name conflicts with XOM classes.
 45    // Thus they cannot be imported, and this class
 46    // must use their fully package qualified names.
 47   
 48   
 49    /**
 50    * <p>
 51    * Converts XOM <code>Document</code> objects to and from DOM
 52    * <code>Document</code> objects. This class can also
 53    * convert many DOM node objects into the corresponding
 54    * XOM node objects. However, the reverse is not possible because
 55    * DOM objects cannot live outside their containing
 56    * <code>Document</code>.
 57    * </p>
 58    *
 59    * @author Elliotte Rusty Harold
 60    * @version 1.2d1
 61    *
 62    */
 63    public class DOMConverter {
 64   
 65   
 66    // prevent instantiation
 67  0 private DOMConverter() {}
 68   
 69   
 70    /**
 71    * <p>
 72    * DOM violates the namespaces 1.0 specification by mapping
 73    * the <code>xmlns</code> prefix to the namespace URI
 74    * <code>http://www.w3.org/2000/xmlns/</code>.
 75    * </p>
 76    */
 77    private final static String XMLNS_NAMESPACE
 78    = "http://www.w3.org/2000/xmlns/";
 79   
 80   
 81    /**
 82    * <p>
 83    * Translates a DOM <code>org.w3c.dom.Document</code> object
 84    * into an equivalent <code>nu.xom.Document</code> object.
 85    * The original DOM document is not changed.
 86    * Some DOM <code>Document</code> objects cannot
 87    * be serialized as namespace well-formed XML, and
 88    * thus cannot be converted to XOM.
 89    * </p>
 90    *
 91    * @param domDocument the DOM document to translate
 92    * @return a XOM document
 93    *
 94    * @throws XMLException if the DOM document is not a well-formed
 95    * XML document
 96    */
 97  13 public static Document convert(org.w3c.dom.Document domDocument) {
 98  13 return convert(domDocument, new NodeFactory());
 99    }
 100   
 101   
 102    // ???? should this return a Nodes instead?
 103    /**
 104    * <p>
 105    * Translates a DOM <code>org.w3c.dom.Document</code> object
 106    * into an equivalent <code>nu.xom.Document</code> object as
 107    * controlled by a factory.
 108    * The original DOM document is not changed.
 109    * Some DOM <code>Document</code> objects cannot
 110    * be serialized as namespace well-formed XML, and
 111    * thus cannot be converted to XOM.
 112    * </p>
 113    *
 114    * @param domDocument the DOM document to translate
 115    * @param factory the factory that converts each DOM node into
 116    * zero or more XOM nodes
 117    *
 118    * @return a XOM document
 119    *
 120    * @throws XMLException if the DOM document is not a well-formed
 121    * XML document
 122    */
 123  16 public static Document convert(
 124    org.w3c.dom.Document domDocument, NodeFactory factory) {
 125   
 126  16 org.w3c.dom.Element domRoot = domDocument.getDocumentElement();
 127  15 Element xomRoot = factory.makeRootElement(
 128    domRoot.getTagName(), domRoot.getNamespaceURI());
 129  15 Document xomDocument = factory.startMakingDocument();
 130  15 xomDocument.setRootElement(xomRoot);
 131  15 Nodes result = convert(domRoot, factory);
 132  15 boolean beforeRoot = true;
 133  15 int p = 0;
 134  15 for (int i = 0; i < result.size(); i++) {
 135  14 Node n = result.get(i);
 136  14 if (beforeRoot) {
 137  14 if (n instanceof Element) {
 138  14 xomDocument.setRootElement((Element) n);
 139  14 beforeRoot = false;
 140    }
 141    else {
 142  0 xomDocument.insertChild(n, p++);
 143    }
 144    }
 145    else {
 146  0 xomDocument.appendChild(n);
 147    }
 148    }
 149   
 150  15 org.w3c.dom.Node current = domDocument.getFirstChild();
 151   
 152    // prolog
 153  15 for (int position = 0;
 154  27 current.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE;
 155    current = current.getNextSibling()) {
 156  12 Nodes nodes = convert(current, factory);
 157    // FIXME fix for multiples
 158  12 for (int i = 0; i < nodes.size(); i++) {
 159  9 xomDocument.insertChild(nodes.get(i), position++);
 160    }
 161    }
 162    // root element
 163  15 current = current.getNextSibling();
 164   
 165    // epilog
 166  15 while (current != null) {
 167  4 Nodes nodes = convert(current, factory);
 168  4 for (int i = 0; i < nodes.size(); i++) {
 169  3 xomDocument.appendChild(nodes.get(i));
 170    }
 171  4 current = current.getNextSibling();
 172    }
 173   
 174  15 return xomDocument;
 175    }
 176   
 177   
 178    /**
 179    * <p>
 180    * Translates a DOM <code>org.w3c.dom.DocumentFragment</code>
 181    * object into an equivalent <code>nu.xom.Nodes</code> object.
 182    * The original DOM document fragment is not changed.
 183    * Some DOM <code>DocumentFragment</code> objects cannot
 184    * be serialized as namespace well-balanced XML, and
 185    * thus cannot be converted to XOM.
 186    * </p>
 187    *
 188    * @param fragment the DOM document fragment to translate
 189    *
 190    * @return a <code>Nodes</code> containing the converted
 191    * fragment members
 192    *
 193    * @throws XMLException if the DOM object is not a well-balanced
 194    * XML fragment
 195    */
 196  1 public static Nodes convert(DocumentFragment fragment) {
 197  1 return convert(fragment, new NodeFactory());
 198    }
 199   
 200   
 201    /**
 202    * <p>
 203    * Translates a DOM <code>org.w3c.dom.DocumentFragment</code>
 204    * object into an equivalent <code>nu.xom.Nodes</code> object,
 205    * converting each DOM node as specified by a factory.
 206    * The original DOM document fragment is not changed.
 207    * Some DOM <code>DocumentFragment</code> objects cannot
 208    * be serialized as namespace well-balanced XML, and
 209    * thus cannot be converted to XOM.
 210    * </p>
 211    *
 212    * @param fragment the DOM document fragment to translate
 213    * @param factory the NodeFactory that converts each DOM node into
 214    * a XOM node
 215    *
 216    * @return a <code>Nodes</code> containing the converted
 217    * fragment members
 218    *
 219    * @throws XMLException if the DOM object is not a well-balanced
 220    * XML fragment
 221    */
 222  1 public static Nodes convert(DocumentFragment fragment, NodeFactory factory) {
 223   
 224  1 Nodes result = new Nodes();
 225  1 NodeList children = fragment.getChildNodes();
 226  1 for (int i = 0; i < children.getLength(); i++) {
 227  3 Nodes nodes = convert(children.item(i), factory);
 228  3 appendNodes(result, nodes);
 229    }
 230   
 231  1 return result;
 232   
 233    }
 234   
 235   
 236  3 private static void appendNodes(Nodes parent, Nodes children) {
 237  3 for (int i = 0; i < children.size(); i++) {
 238  3 parent.append(children.get(i));
 239    }
 240    }
 241   
 242   
 243  76 private static Nodes convert(org.w3c.dom.Node node, NodeFactory factory) {
 244   
 245  76 int type = node.getNodeType();
 246  76 switch (type) {
 247  1 case org.w3c.dom.Node.ELEMENT_NODE:
 248  1 return convert((org.w3c.dom.Element) node, factory);
 249  9 case org.w3c.dom.Node.COMMENT_NODE:
 250  9 return convert((org.w3c.dom.Comment) node, factory);
 251  4 case org.w3c.dom.Node.DOCUMENT_TYPE_NODE:
 252  4 return convert((org.w3c.dom.DocumentType) node, factory);
 253  57 case org.w3c.dom.Node.TEXT_NODE:
 254  57 return convert((org.w3c.dom.Text) node, factory);
 255  1 case org.w3c.dom.Node.CDATA_SECTION_NODE:
 256  1 return convert((org.w3c.dom.Text) node, factory);
 257  4 case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
 258  4 return convert((org.w3c.dom.ProcessingInstruction) node, factory);
 259  0 default:
 260  0 throw new XMLException(
 261    "Unexpected DOM node type: " + type);
 262    }
 263   
 264    }
 265   
 266   
 267    /**
 268    * <p>
 269    * Translates a DOM <code>org.w3c.dom.Comment</code> object
 270    * into an equivalent <code>nu.xom.Comment</code> object.
 271    * The original DOM object is not changed.
 272    * Some DOM <code>Comment</code> objects cannot
 273    * be serialized as well-formed XML, and
 274    * thus cannot be converted to XOM.
 275    * </p>
 276    *
 277    * @param comment the DOM comment to translate
 278    * @return a XOM comment
 279    *
 280    * @throws XMLException if the DOM comment is not a well-formed
 281    * XML comment
 282    */
 283  1 public static Comment convert(org.w3c.dom.Comment comment) {
 284  1 return new Comment(comment.getNodeValue());
 285    }
 286   
 287  9 private static Nodes convert(org.w3c.dom.Comment comment, NodeFactory factory) {
 288  9 return factory.makeComment(comment.getNodeValue());
 289    }
 290   
 291    /**
 292    * <p>
 293    * Translates a DOM <code>org.w3c.dom.Text</code> object
 294    * into an equivalent <code>nu.xom.Text</code>.
 295    * This method will also convert <code>org.w3c.dom.CDATA</code>
 296    * objects. The original DOM object is not changed.
 297    * Some DOM <code>Text</code> objects cannot
 298    * be serialized as well-formed XML, and
 299    * thus cannot be converted to XOM.
 300    * </p>
 301    *
 302    * @param text the DOM text to translate
 303    * @return a XOM text
 304    *
 305    * @throws XMLException if the DOM text is not a well-formed
 306    * XML text
 307    */
 308  2 public static Text convert(org.w3c.dom.Text text) {
 309  2 return new Text(text.getNodeValue());
 310    }
 311   
 312   
 313  58 private static Nodes convert(org.w3c.dom.Text text, NodeFactory factory) {
 314  58 return factory.makeText(text.getNodeValue());
 315    }
 316   
 317   
 318    /**
 319    * <p>
 320    * Translates a DOM <code>org.w3c.dom.Attr</code> object
 321    * into an equivalent <code>nu.xom.Attribute</code> object.
 322    * The original DOM object is not changed.
 323    * Some DOM <code>Attr</code> objects cannot
 324    * be serialized as well-formed XML, and
 325    * thus cannot be converted to XOM. Furthermore, DOM uses
 326    * <code>Attr</code> objects to represent namespace declarations.
 327    * XOM does not. Converting an <code>Attr</code> object that
 328    * represents an <code>xmlns</code> or
 329    * <code>xmlns:<i>prefix</i></code> attribute will cause an
 330    * exception.
 331    * </p>
 332    *
 333    * @param attribute the DOM <code>Attr</code> to translate
 334    * @return the equivalent XOM <code>Attribute</code>
 335    *
 336    * @throws XMLException if the DOM <code>Attr</code>
 337    * is a namespace declaration or is not a well-formed
 338    * XML attribute
 339    */
 340  3 public static Attribute convert(Attr attribute) {
 341   
 342  3 String name = attribute.getName();
 343  3 String uri = attribute.getNamespaceURI();
 344  1 if (uri == null) uri = "";
 345  3 return new Attribute(name, uri, attribute.getNodeValue());
 346   
 347    }
 348   
 349   
 350  0 private static Attribute convert(Attr attribute, NodeFactory factory) {
 351   
 352  0 String name = attribute.getName();
 353  0 String uri = attribute.getNamespaceURI();
 354  0 if (uri == null) uri = "";
 355  0 Nodes result = factory.makeAttribute(name, uri, attribute.getNodeValue(), Attribute.Type.UNDECLARED);
 356  0 return (Attribute) result.get(0);
 357   
 358    }
 359   
 360   
 361    /**
 362    * <p>
 363    * Translates a DOM <code>org.w3c.dom.ProcessingInstruction</code>
 364    * object into an equivalent
 365    * <code>nu.xom.ProcessingInstruction</code> object.
 366    * The original DOM object is not changed.
 367    * Some DOM <code>ProcessingInstruction</code> objects cannot
 368    * be serialized as well-formed XML, and
 369    * thus cannot be converted to XOM.
 370    * </p>
 371    *
 372    * @param pi the DOM <code>ProcessingInstruction</code> to
 373    * convert
 374    * @return a XOM <code>ProcessingInstruction</code>
 375    *
 376    * @throws XMLException if the DOM <code>ProcessingInstruction</code>
 377    * is not a well-formed XML processing instruction
 378    */
 379  1 public static ProcessingInstruction convert(
 380    org.w3c.dom.ProcessingInstruction pi) {
 381  1 return new ProcessingInstruction(pi.getTarget(), pi.getNodeValue());
 382    }
 383   
 384   
 385  4 private static Nodes convert(
 386    org.w3c.dom.ProcessingInstruction pi, NodeFactory factory) {
 387  4 return factory.makeProcessingInstruction(pi.getTarget(), pi.getNodeValue());
 388    }
 389   
 390   
 391    /**
 392    * <p>
 393    * Translates a DOM <code>org.w3c.dom.DocumentType</code>
 394    * object into an equivalent <code>nu.xom.DocType</code> object.
 395    * The original DOM object is not changed. Some DOM
 396    * <code>DocumentType</code> objects cannot be serialized as
 397    * well-formed XML, and thus cannot be converted to XOM.
 398    * </p>
 399    *
 400    * @param doctype the DOM <code>DocumentType</code> to convert
 401    * @return the equivalent XOM <code>DocType</code>
 402    *
 403    * @throws XMLException if the DOM <code>DocumentType</code>
 404    * is not a well-formed XML document type declaration
 405    */
 406  3 public static DocType convert(org.w3c.dom.DocumentType doctype) {
 407   
 408  3 DocType result =
 409    new DocType(
 410    doctype.getName(),
 411    doctype.getPublicId(),
 412    doctype.getSystemId());
 413  3 result.setInternalDTDSubset(doctype.getInternalSubset());
 414   
 415  3 return result;
 416   
 417    }
 418   
 419   
 420  4 private static Nodes convert(org.w3c.dom.DocumentType doctype, NodeFactory factory) {
 421   
 422  4 Nodes nodes = factory.makeDocType(
 423    doctype.getName(),
 424    doctype.getPublicId(),
 425    doctype.getSystemId());
 426  4 for (int i = 0; i < nodes.size(); i++) {
 427  3 Node node = nodes.get(i);
 428  3 if (node instanceof DocType) {
 429  3 ((DocType) node).setInternalDTDSubset(doctype.getInternalSubset());
 430  3 break;
 431    }
 432    }
 433   
 434  4 return nodes;
 435   
 436    }
 437   
 438   
 439    /**
 440    * <p>
 441    * Translates a DOM <code>org.w3c.dom.Element</code>
 442    * object into an equivalent <code>nu.xom.Element</code> object.
 443    * The original DOM object is not changed. Some DOM
 444    * <code>Element</code> objects cannot be serialized as
 445    * namespace well-formed XML, and thus cannot be converted to XOM.
 446    * </p>
 447    *
 448    * @param element the DOM <code>Element</code> to convert
 449    * @return the equivalent XOM <code>Element</code>
 450    *
 451    * @throws XMLException if the DOM <code>Element</code>
 452    * is not a well-formed XML element
 453    */
 454  3 public static Element convert(org.w3c.dom.Element element) {
 455  3 return (Element) convert(element, new NodeFactory()).get(0);
 456    }
 457   
 458   
 459  19 private static Nodes convert(org.w3c.dom.Element element, NodeFactory factory) {
 460   
 461  19 org.w3c.dom.Node current = element;
 462  19 Element result = makeElement(element, factory);
 463   
 464  18 if (result == null) {
 465  0 Nodes out = new Nodes();
 466  0 NodeList children = element.getChildNodes();
 467  0 for (int i = 0; i < children.getLength(); i++) {
 468  0 Nodes temp = convert(children.item(i), factory);
 469  0 for (int j = 0; j < temp.size(); j++) {
 470  0 out.append(temp.get(j));
 471    }
 472    }
 473  0 return out;
 474    }
 475   
 476   
 477  18 ParentNode parent = result;
 478  18 boolean backtracking = false;
 479  18 while (true) {
 480  377 if (current.hasChildNodes() && !backtracking) {
 481  153 current = current.getFirstChild();
 482  153 backtracking = false;
 483    }
 484  224 else if (current == element) {
 485  18 break;
 486    }
 487  206 else if (current.getNextSibling() != null) {
 488  53 current = current.getNextSibling();
 489  53 backtracking = false;
 490    }
 491    else {
 492  153 current = current.getParentNode();
 493  153 backtracking = true;
 494  134 if (parent.getParent() != null) parent = parent.getParent();
 495  153 continue;
 496    }
 497   
 498  206 int type = current.getNodeType();
 499  206 if (type == org.w3c.dom.Node.ELEMENT_NODE) {
 500  149 Element child = makeElement((org.w3c.dom.Element) current, factory);
 501  149 if (child != null) {
 502  143 parent.appendChild(child);
 503  134 if (current.hasChildNodes()) parent = child;
 504    }
 505    }
 506    else {
 507  57 Nodes children = convert(current, factory);
 508  57 for (int i = 0; i < children.size(); i++) {
 509  50 parent.appendChild(children.get(i));
 510    }
 511    }
 512   
 513    }
 514   
 515  18 return factory.finishMakingElement(result);
 516   
 517    }
 518   
 519   
 520  168 private static Element makeElement(org.w3c.dom.Element element, NodeFactory factory) {
 521   
 522  168 String namespaceURI = element.getNamespaceURI();
 523  167 String tagName = element.getTagName();
 524   
 525  167 Element result;
 526  167 if (element.getParentNode() == null
 527    || element.getParentNode().getNodeType() == org.w3c.dom.Node.DOCUMENT_NODE) {
 528  17 result = factory.makeRootElement(tagName, namespaceURI);
 529    }
 530    else {
 531  150 result = factory.startMakingElement(tagName, namespaceURI);
 532    }
 533  6 if (result == null) return null;
 534   
 535    // fill element's attributes and additional namespace declarations
 536  161 NamedNodeMap attributes = element.getAttributes();
 537  161 for (int i = 0; i < attributes.getLength(); i++) {
 538  35 org.w3c.dom.Attr attribute = (org.w3c.dom.Attr) attributes.item(i);
 539  35 String name = attribute.getName();
 540  35 String uri = attribute.getNamespaceURI();
 541  35 String value = attribute.getValue();
 542  7 if (uri == null) uri = "";
 543  35 if (uri.equals(XMLNS_NAMESPACE)) {
 544  7 if (name.equals("xmlns")) continue;
 545  17 String prefix = name.substring(name.indexOf(':') + 1);
 546  17 String currentURI = result.getNamespaceURI(prefix);
 547  17 if (!value.equals(currentURI)) {
 548  8 result.addNamespaceDeclaration(prefix, value);
 549    }
 550    }
 551    else {
 552  11 Nodes nodes = factory.makeAttribute(name, uri, value, Attribute.Type.UNDECLARED);
 553  11 for (int j = 0; j < nodes.size(); j++) {
 554  9 Node child = nodes.get(j);
 555  9 if (child instanceof Attribute) result.addAttribute((Attribute) child);
 556  0 else result.appendChild(child);
 557    }
 558    }
 559    }
 560  161 return result;
 561   
 562    }
 563   
 564   
 565    /**
 566    * <p>
 567    * Translates a XOM <code>nu.xom.Document</code> object
 568    * into an equivalent <code>org.w3c.dom.Document</code>
 569    * object. The original XOM document is not changed.
 570    * Since DOM2 internal subsets are read-only,
 571    * the internal DTD subset is not converted.
 572    * All other aspects of the document should be
 573    * translated without a problem.
 574    * </p>
 575    *
 576    * @param document the XOM document to translate
 577    * @param impl the specific DOM implementation into which this
 578    * document will be converted
 579    *
 580    * @return a DOM document
 581    */
 582  14 public static org.w3c.dom.Document convert(Document document,
 583    DOMImplementation impl) {
 584   
 585  14 Element root = document.getRootElement();
 586  13 String rootName = root.getQualifiedName();
 587  13 String rootNamespace = root.getNamespaceURI();
 588  13 DocType doctype = document.getDocType();
 589  13 DocumentType domDOCTYPE = null;
 590  13 if (doctype != null) {
 591  1 domDOCTYPE = impl.createDocumentType(rootName,
 592    doctype.getPublicID(), doctype.getSystemID());
 593    }
 594   
 595  13 org.w3c.dom.Document domDoc
 596    = impl.createDocument(rootNamespace, rootName, domDOCTYPE);
 597  13 org.w3c.dom.Element domRoot = domDoc.getDocumentElement();
 598   
 599  13 boolean beforeRoot = true;
 600  13 for (int i = 0; i < document.getChildCount(); i++) {
 601  17 Node original = document.getChild(i);
 602    // Need to test positioning of doctype
 603  1 if (original instanceof DocType) continue;
 604  16 else if (original instanceof Element) {
 605  13 convert((Element) original, domDoc);
 606  13 beforeRoot = false;
 607    }
 608    else {
 609  3 org.w3c.dom.Node domNode = convert(original, domDoc);
 610  2 if (beforeRoot) domDoc.insertBefore(domNode, domRoot);
 611  1 else domDoc.appendChild(domNode);
 612    }
 613    }
 614   
 615  13 return domDoc;
 616   
 617    }
 618   
 619   
 620  41 private static org.w3c.dom.Node convert(
 621    Node node, org.w3c.dom.Document document) {
 622   
 623  41 if (node instanceof Text) {
 624  38 return convert((Text) node, document);
 625    }
 626  3 else if (node instanceof Comment) {
 627  2 return convert((Comment) node, document);
 628    }
 629  1 else if (node instanceof ProcessingInstruction) {
 630  1 return convert((ProcessingInstruction) node, document);
 631    }
 632    // The non-recursive algorithm converts elements directly.
 633    // It does not pass through this method.
 634    else {
 635  0 throw new XMLException(
 636    "Unexpected node type: " + node.getClass().getName()
 637    );
 638    }
 639   
 640    }
 641   
 642   
 643  2 private static org.w3c.dom.Comment convert(
 644    Comment comment, org.w3c.dom.Document document) {
 645  2 return document.createComment(comment.getValue());
 646    }
 647   
 648   
 649  38 private static org.w3c.dom.Text convert(
 650    Text text, org.w3c.dom.Document document) {
 651  38 return document.createTextNode(text.getValue());
 652    }
 653   
 654   
 655  1 private static org.w3c.dom.ProcessingInstruction convert(
 656    ProcessingInstruction pi, org.w3c.dom.Document document) {
 657  1 return document.createProcessingInstruction(
 658    pi.getTarget(), pi.getValue());
 659    }
 660   
 661   
 662  13 private static org.w3c.dom.Element convert(
 663    Element xomElement, org.w3c.dom.Document document) {
 664   
 665  13 org.w3c.dom.Element domResult = makeElement(xomElement, document);
 666  13 org.w3c.dom.Node domParent = domResult;
 667  13 Node xomCurrent = xomElement;
 668  13 int index = 0;
 669  13 int[] indexes = new int[10];
 670  13 int top = 0;
 671  13 indexes[0] = 0;
 672  13 boolean end = false;
 673  13 while (true) {
 674   
 675  304 if (!end && xomCurrent.getChildCount() > 0) {
 676  132 xomCurrent = xomCurrent.getChild(0);
 677  132 index = 0;
 678  132 top++;
 679  132 indexes = grow(indexes, top);
 680  132 indexes[top] = 0;
 681    }
 682    else {
 683  172 end = false;
 684  172 ParentNode xomParent = xomCurrent.getParent();
 685  172 org.w3c.dom.Node grandparent = domParent.getParentNode();
 686  172 if (grandparent.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE
 687    && xomCurrent instanceof Element) {
 688  131 domParent = grandparent;
 689    }
 690  172 if (xomParent.getChildCount() - 1 == index) {
 691  135 xomCurrent = xomParent;
 692  135 top--;
 693  10 if (xomCurrent == xomElement) break;
 694  125 ParentNode tp = xomCurrent.getParent();
 695  3 if (tp == null) break;
 696  122 index = indexes[top];
 697  122 end = true;
 698  122 continue;
 699    }
 700    else {
 701  37 index++;
 702  37 indexes[top] = index;
 703  37 xomCurrent = xomParent.getChild(index);
 704    }
 705    }
 706   
 707  169 if (xomCurrent instanceof Element) {
 708  131 Element currentElement = (Element) xomCurrent;
 709  131 org.w3c.dom.Element child = makeElement(currentElement, document);
 710  131 domParent.appendChild(child);
 711  131 domParent = child;
 712    }
 713    else {
 714  38 org.w3c.dom.Node child = convert(xomCurrent, document);
 715  38 domParent.appendChild(child);
 716    }
 717   
 718    } // end while
 719   
 720  13 return domResult;
 721   
 722    }
 723   
 724   
 725  132 private static int[] grow(int[] indexes, int top) {
 726   
 727  128 if (top < indexes.length) return indexes;
 728  4 int[] result = new int[indexes.length*2];
 729  4 System.arraycopy(indexes, 0, result, 0, indexes.length);
 730  4 return result;
 731   
 732    }
 733   
 734   
 735  144 private static org.w3c.dom.Element makeElement(
 736    Element element, org.w3c.dom.Document document) {
 737   
 738  144 org.w3c.dom.Element result;
 739  144 String namespace = element.getNamespaceURI();
 740   
 741  144 if (element.getParent() instanceof Document) {
 742  13 result = document.getDocumentElement();
 743    }
 744  131 else if (namespace.equals("")) {
 745  112 result = document.createElement(
 746    element.getQualifiedName());
 747    }
 748    else {
 749  19 result = document.createElementNS(
 750    namespace, element.getQualifiedName());
 751    }
 752   
 753  144 int attributeCount = element.getAttributeCount();
 754  144 for (int i = 0; i < attributeCount; i++) {
 755  7 Attribute attribute = element.getAttribute(i);
 756  7 String attns = attribute.getNamespaceURI();
 757  7 Attr attr;
 758  7 if (attns.equals("")) {
 759  3 attr = document.createAttribute(attribute.getLocalName());
 760  3 result.setAttributeNode(attr);
 761    }
 762    else {
 763  4 attr = document.createAttributeNS(
 764    attns, attribute.getQualifiedName()
 765    );
 766  4 result.setAttributeNodeNS(attr);
 767    }
 768  7 attr.setValue(attribute.getValue());
 769    }
 770   
 771  144 int namespaceCount = element.getNamespaceDeclarationCount();
 772  144 for (int i = 0; i < namespaceCount; i++) {
 773  148 String additionalPrefix = element.getNamespacePrefix(i);
 774  148 String uri = element.getNamespaceURI(additionalPrefix);
 775   
 776  148 ParentNode parentNode = element.getParent();
 777  148 if (parentNode instanceof Element) {
 778  135 Element parentElement = (Element) parentNode;
 779  135 if (uri.equals(
 780    parentElement.getNamespaceURI(additionalPrefix))) {
 781  127 continue;
 782    }
 783    }
 784  13 else if (uri.equals("")) { //parent is Document or null
 785  8 continue; // no need to say xmlns=""
 786    }
 787   
 788  13 if ("".equals(additionalPrefix)) {
 789  4 Attr attr = document.createAttributeNS(
 790    XMLNS_NAMESPACE, "xmlns"
 791    );
 792  4 result.setAttributeNodeNS(attr);
 793  4 attr.setValue(uri);
 794    }
 795    else {
 796  9 Attr attr = document.createAttributeNS(
 797    XMLNS_NAMESPACE,
 798    "xmlns:" + additionalPrefix
 799    );
 800  9 result.setAttributeNodeNS(attr);
 801  9 attr.setValue(uri);
 802    }
 803    }
 804   
 805  144 return result;
 806   
 807    }
 808   
 809   
 810    }