You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xerces.apache.org by rp...@locus.apache.org on 2000/01/29 00:29:25 UTC

cvs commit: xml-xerces/java/tests/dom/DOMRangeTest RangeTest.java

rpfeiffe    00/01/28 15:29:25

  Added:       java/tests/dom/DOMRangeTest RangeTest.java
  Log:
  Checkin the initial RangeText
  
  Revision  Changes    Path
  1.1                  xml-xerces/java/tests/dom/DOMRangeTest/RangeTest.java
  
  Index: RangeTest.java
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 1999 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Xerces" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 1999, International
   * Business Machines, Inc., http://www.apache.org.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package dom.DOMRangeTest;
  import org.apache.xerces.parsers.*;
  import org.apache.xerces.dom.*;
  import org.apache.xerces.dom.DocumentImpl;
  import org.apache.xerces.dom.range.*;
  
  import org.w3c.dom.*;
  import org.w3c.dom.Element;
  import org.w3c.dom.range.*;
  import org.w3c.dom.range.RangeException;
  
  import java.io.*;
  import dom.DOMWriter;
  import org.xml.sax.InputSource;
  
  /** This RangeTest tests all of the cases delineated as examples
   *  in the DOM Level 2 Range specification, and a few others.
   *  <p>These do not by any means completely test the API and 
   *  corner cases. 
   */
  public class RangeTest {
      
      static final boolean DEBUG = false;
      
      static final String [] tests = {
          "<FOO>AB<MOO>CD</MOO>CD</FOO>",
          "<FOO>A<MOO>BC</MOO>DE</FOO>",
          "<FOO>XY<BAR>ZW</BAR>Q</FOO>",
          "<FOO><BAR1>AB</BAR1><BAR2/><BAR3>CD</BAR3></FOO>",
          "<A><B><M/><C><D/><E/><F/><HELLO/></C><N/><O/></B>"+
          "<Z><X/><Y/></Z>"+
          "<G/><Q><V/><W/></Q></A>"
      };
      static final String [] deleteResult = {
          "<FOO>ACD</FOO>",
          "<FOO>A<MOO>B</MOO>E</FOO>",
          "<FOO>X<BAR>W</BAR>Q</FOO>",
          "<FOO><BAR1>A</BAR1><BAR3>D</BAR3></FOO>",
          "<A><B><M></M><C><D></D></C></B><Q><W></W></Q></A>"
      };
      static final String [] extractResult = {
          "B<MOO>CD</MOO>",
          "<MOO>C</MOO>D",
          "Y<BAR>Z</BAR>",
          "<BAR1>B</BAR1><BAR2></BAR2><BAR3>C</BAR3>",
          "<B><C><E></E><F></F><HELLO></HELLO></C>"+
          "<N></N><O></O></B><Z><X></X><Y></Y></Z><G></G><Q><V></V></Q>"
      };
      
      static final String INSERT="***";
      static final String [] insertResult = {
  "<FOO>A"+INSERT+"B<MOO>CD</MOO>CD</FOO>",
  "<FOO>A<MOO>B"+INSERT+"C</MOO>DE</FOO>",
  "<FOO>X"+INSERT+"Y<BAR>ZW</BAR>Q</FOO>",
  "<FOO><BAR1>A"+INSERT+"B</BAR1><BAR2></BAR2><BAR3>CD</BAR3></FOO>",
  "<A><B><M></M><C><D></D>"+INSERT+"<E></E><F></F><HELLO></HELLO></C>"+
  "<N></N><O></O></B><Z><X></X><Y></Y></Z><G></G><Q><V></V><W></W></Q></A>"
      };
      
  
      static final String SURROUND="SURROUND";
  
      static final String [] surroundResult = {
  "<FOO>A<"+SURROUND+">B<MOO>CD</MOO>C</"+SURROUND+">D</FOO>",
  "<FOO>A<MOO>B<"+SURROUND+">C</"+SURROUND+"></MOO>DE</FOO>",
  "<FOO>X<"+SURROUND+">Y<BAR>ZW</BAR></"+SURROUND+">Q</FOO>",
  "<FOO><BAR1>AB</BAR1><"+SURROUND+"><BAR2></BAR2></"+SURROUND+"><BAR3>CD</BAR3></FOO>",
  "<A><B><M></M><C><D></D><E></E><F></F><HELLO></HELLO></C>"+
  "<N></N><O></O></B><Z><"+SURROUND+"><X></X><Y></Y></"+SURROUND+"></Z>"+
  "<G></G><Q><V></V><W></W></Q></A>"
      };
      
      static final String [] rangeDelete = {
      "<P>Abcd efgh The Range ijkl</P>",
      "<p>Abcd efgh The Range ijkl</p>",
      "<P>ABCD efgh The <EM>Range</EM> ijkl</P>",
      "<P>Abcd efgh The Range ijkl</P>",
      "<P>Abcd <EM>efgh The Range ij</EM>kl</P>"
      };
      //
      static final String [] rangeDeleteResult = {
      "<P>Abcd ^Range ijkl</P>",
      "<p>Abcd ^kl</p>",
      "<P>ABCD ^<EM>ange</EM> ijkl</P>",
      "<P>Abcd ^he Range ijkl</P>",
      "<P>Abcd ^kl</P>"
      };
      
      static final String INSERT2="<P>Abcd efgh XY blah ijkl</P>";
      static final String INSERTED_TEXT = "INSERTED TEXT";
      
      static final String [] rangeInsertResult = {
      "<P>Abcd efgh INSERTED TEXTXY blah ijkl</P>",
      "<P>Abcd efgh XINSERTED TEXTY blah ijkl</P>",
      "<P>Abcd efgh XYINSERTED TEXT blah ijkl</P>",
      "<P>Abcd efgh XY blahINSERTED TEXT ijkl</P>"
      };
      
      
      public static void main(String args[]) {
          // is there anything to do?
          if ( args.length == 0 ) {
              printUsage();
              System.exit(1);
          }
          new RangeTest(args[0]);
      }
      
     /** Prints the usage. */
     private static void printUsage() {
  
        System.err.println("usage: java dom.DOMRangeTest.RangeTest (options) ...");
        System.err.println();
        System.err.println("options:");
        System.err.println("  all             all tests");
        System.err.println("  delete          delete test");
        System.err.println("  extract         extract test");
        System.err.println("  clone           clone test");
        System.err.println("  insert          insert test");
        System.err.println("  surround        surround test");
        System.err.println("  insert2         insert mutation test");
        System.err.println("  delete2         delete mutation test");
  
     } // printUsage()
      
      
      public RangeTest(String arg) {
          if (arg.equals("all")) {
              boolean all = false;
              all = performTest("delete");
              all = performTest("extract")&&all;
              all = performTest("clone")&&all;
              all = performTest("insert")&&all;
              all = performTest("surround")&&all;
              all = performTest("insert2")&&all;
              all = performTest("delete2")&&all;
              if (all) 
                  System.out.println("*** ALL TESTS PASSED! ***");
              else 
                  System.out.println("*** ONE OR MORE TESTS FAILED! ***");
              
          } else {
              performTest(arg);            
          }
      }
      
      public boolean performTest(String arg) {
          boolean passed = true;
          try {
              DOMWriter writer = new DOMWriter(false);
              DOMParser parser = new DOMParser();
              if (!arg.equals("delete2") && !arg.equals("insert2")) {
              System.out.println("\n*************** Test == "+arg+" ***************");
              for (int i = 0; i < tests.length; i++) {
                  System.out.println("\n\nTest["+i+"]");
                  System.out.println("\nBefore "+arg+": document="+tests[i]+":");
                  parser.parse(new InputSource(new StringReader(tests[i])));
                  DocumentImpl document = (DocumentImpl)parser.getDocument();
                  Range range = document.createRange();
                  Node root = document.getDocumentElement();
                  boolean surround = false;
                  Node surroundNode=document.createElement(SURROUND);
                  if (arg.equals("surround")) {
                      surround = true;
                  }
                  
                  if (i == 0) { 
                      range.setStart(root.getFirstChild(), 1);
                      range.setEndBefore(root.getLastChild());
                      if (surround)
                          range.setEnd(root.getLastChild(),1);
                      
                  }
                  else if (i == 1) {
                      Node n1 = root.getFirstChild().getNextSibling().
                      getFirstChild();
                      range.setStart(n1, 1);
                      range.setEnd(root.getLastChild(), 1);
                      if (surround)
                          range.setEnd(n1,2);
                  }
                  else if (i == 2) {
                      range.setStart(root.getFirstChild(), 1);
                      Node n2 = root.getFirstChild().getNextSibling().getFirstChild();
                      range.setEnd(n2, 1);
                      if (surround)
                          range.setEndBefore(root.getLastChild());
                  }
                  else if (i == 3) {
                      Node n3 = root.getFirstChild().getFirstChild();
                      range.setStart(n3, 1);
                      range.setEnd(root.getLastChild().getFirstChild(), 1);
                      if (surround) {
                          range.selectNode(root.getFirstChild().getNextSibling());
                      }
                  }
                  else if (i == 4) {
                      Node n4 = root.getFirstChild().getFirstChild().getNextSibling().getFirstChild();
                      range.setStartAfter(n4);
                      range.setEndAfter(root.getLastChild().getFirstChild());
                      if (surround) {
                          range.selectNodeContents(root.getFirstChild().getNextSibling());
                      }
                  }
                  
                  System.out.println("range.toString="+range.toString());
                  DocumentFragment frag = null;
                  
                  if (arg.equals("surround")) {
                      try {
                          System.out.println("surroundNode="+surroundNode);
                          range.surroundContents(surroundNode);
                      } catch (org.w3c.dom.range.RangeException e) {
                          System.out.println(e);
                      }
                     String result = toString(document);
                     System.out.println("After surround: document="+result+":");
                     if (!result.equals(surroundResult[i])) {
                          System.out.println("Should be: document="+surroundResult[i]+":");
                          passed = false;
                          System.out.println("Test FAILED!");
                          System.out.println("*** Surround document Test["+i+"] FAILED!");
                     }
                  }
                  
                  if (arg.equals("insert")) {
                      range.insertNode(document.createTextNode(INSERT));
                     String result = toString(document);
                     System.out.println("After  insert: document="+result+":");
                     if (!result.equals(insertResult[i])) {
                          System.out.println("Should be: document="+insertResult[i]+":");
                          passed = false;
                          System.out.println("Test FAILED!");
                          System.out.println("*** Insert document Test["+i+"] FAILED!");
                     }
                      
                  } else 
                  if (arg.equals("delete")) {
                     range.deleteContents();
                     String result = toString(document);
                     System.out.println("After delete:"+result+":");
                     if (!result.equals(deleteResult[i])) {
                          System.out.println("Should be: document="+deleteResult[i]+":");
                          passed = false;
                          System.out.println("Test FAILED!");
                          System.out.println("*** Delete document Test["+i+"] FAILED!");
                     }
                  }
                  else 
                  if (arg.equals("extract")) {
                      frag = range.extractContents();
                      //range.insertNode(document.createTextNode("^"));
                     String result = toString(document);
                     System.out.println("After extract: document="+result+":");
                     if (!result.equals(deleteResult[i])) {
                          System.out.println("Should be: document="+deleteResult[i]+":");
                          passed = false;
                          System.out.println("*** Extract document Test["+i+"] FAILED!");
                     }
                     String fragResult = toString(frag);
                     System.out.println("After extract: fragment="+fragResult+":");
                     if (!fragResult.equals(extractResult[i])) {
                          System.out.println("Should be: fragment="+extractResult[i]+":");
                          passed = false;
                          System.out.println("*** Extract Fragment Test["+i+"] FAILED!");
                     }
                  }
                     
                  else 
                  if (arg.equals("clone")) {
                      frag = range.cloneContents();
                     String fragResult = toString(frag);
                     System.out.println("After clone: fragment="+fragResult);
                     if (!fragResult.equals(extractResult[i])) {
                          System.out.println("Should be: fragment="+extractResult[i]+":");
                          passed = false;
                          System.out.println("*** Clone Fragment Test["+i+"] FAILED!");
                     }
                  }
                  
              }
              
              } else
              if (arg.equals("insert2")) {
              System.out.println("\n*************** Test == "+arg+" ***************");
              for (int i = 0; i < 4; i++) {
  
                  System.out.println("\n\nTest["+i+"]");
                  System.out.println("\nBefore "+arg+": document="+INSERT2+":");
                  parser.parse(new InputSource(new StringReader(INSERT2)));
                  DocumentImpl document = (DocumentImpl)parser.getDocument();
                  Node root = document.getDocumentElement();
                  Range range = document.createRange();
                  range.setStart(root.getFirstChild(),11);
                  range.setEnd(root.getFirstChild(),18);
                  Range rangei = document.createRange();
                  if (i == 0) { 
                      rangei.setStart(root.getFirstChild(), 10);
                      rangei.setEnd(root.getFirstChild(), 10);
                  }
                  if (i == 1) { 
                      rangei.setStart(root.getFirstChild(), 11);
                      rangei.setEnd(root.getFirstChild(), 11);
                  }
                  if (i == 2) { 
                      rangei.setStart(root.getFirstChild(), 12);
                      rangei.setEnd(root.getFirstChild(), 12);
                  }
                  if (i == 3) { 
                      rangei.setStart(root.getFirstChild(), 17);
                      rangei.setEnd(root.getFirstChild(), 17);
                  }
                  //System.out.println("range: start1=="+range.getStartContainer());
                  //root.insertBefore(document.createTextNode("YES!"), root.getFirstChild());
                  //System.out.println("range: start2=="+range.getStartContainer());
     
                  if (DEBUG) System.out.println("before insert start="+range.getStartOffset());
                  if (DEBUG) System.out.println("before insert end="+range.getEndOffset());
                  rangei.insertNode(document.createTextNode(INSERTED_TEXT));
                  if (DEBUG) System.out.println("after insert start="+range.getStartOffset());
                  if (DEBUG) System.out.println("after insert end="+range.getEndOffset());
                  
                  String result = toString(document);
                  System.out.println("After insert2: document="+result+":");
                  if (!result.equals(rangeInsertResult[i])) {
                      System.out.println("Should be: document="+rangeInsertResult[i]+":");
                      passed = false;
                      System.out.println("Test FAILED!");
                      System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
                  }
              }
              } else
              if (arg.equals("delete2")) {
              //
              // Range Deletion, acting upon another range.
              //
         
              System.out.println("\n*************** Test == "+arg+" ***************");
              for (int i = 0; i < rangeDelete.length; i++) {
                  System.out.println("\n\nTest["+i+"]");
                  System.out.println("\nBefore "+arg+": document="+rangeDelete[i]+":");
                  parser.parse(new InputSource(new StringReader(rangeDelete[i])));
                  DocumentImpl document = (DocumentImpl)parser.getDocument();
                  Range range = document.createRange();
                  Range ranged = document.createRange();
                  Node root = document.getDocumentElement();
                  boolean surround = false;
                  Node surroundNode=document.createElement(SURROUND);
                  if (arg.equals("surround")) {
                      surround = true;
                  }
                  
                  if (i == 0) { 
                      ranged.setStart(root.getFirstChild(), 5);
                      ranged.setEnd(root.getFirstChild(), 14);
                      
                      range.setStart(root.getFirstChild(), 11);
                      range.setEnd(root.getFirstChild(), 19);
                  }
                  else if (i == 1) {
                      ranged.setStart(root.getFirstChild(), 5);
                      ranged.setEnd(root.getFirstChild(), 22);
                      
                      range.setStart(root.getFirstChild(), 11);
                      range.setEnd(root.getFirstChild(), 21);
                  }
                  else if (i == 2) {
                      ranged.setStart(root.getFirstChild(), 5);
                      ranged.setEnd(root.getFirstChild().getNextSibling()
                          .getFirstChild(), 1);
                          
                      range.setStart(root.getFirstChild(), 11);
                      
                      range.setEndAfter(root.getFirstChild().getNextSibling()
                          .getFirstChild());
                  }
                  else if (i == 3) {
                      ranged.setStart(root.getFirstChild(), 5);
                      ranged.setEnd(root.getFirstChild(), 11);
                      
                      range.setStart(root.getFirstChild(), 11);
                      range.setEnd(root.getFirstChild(), 21);
                  }
                  else if (i == 4) {
                      ranged.selectNode(root.getFirstChild().getNextSibling());
                      
                      range.setStart(root.getFirstChild().getNextSibling()
                          .getFirstChild(), 6);
                      range.setEnd(root.getFirstChild().getNextSibling()
                          .getFirstChild(), 15);
                  }
                  
                  DocumentFragment frag = null;
                  
                  if (arg.equals("delete2")) {
                      if (DEBUG) {
                     System.out.println("BEFORE deleteContents()");
                     System.out.println("ranged: startc="+ranged.getStartContainer());
                     System.out.println("ranged: starto="+ranged.getStartOffset());
                     System.out.println("ranged:   endc="+ranged.getEndContainer());
                     System.out.println("ranged:   endo="+ranged.getEndOffset());
               
                     System.out.println("range: startc="+range.getStartContainer());
                     System.out.println("range: starto="+range.getStartOffset());
                     System.out.println("range:   endc="+range.getEndContainer());
                     System.out.println("range:   endo="+range.getEndOffset());
                      }
                     ranged.deleteContents();
                     String result = null;
                     if (DEBUG) {
                     System.out.println("AFTER deleteContents()");
                     result = toString(document);
                     System.out.println("ranged: startc="+ranged.getStartContainer());
                     System.out.println("ranged: starto="+ranged.getStartOffset());
                     System.out.println("ranged:   endc="+ranged.getEndContainer());
                     System.out.println("ranged:   endo="+ranged.getEndOffset());
               
                     System.out.println("range: startc="+range.getStartContainer());
                     System.out.println("range: starto="+range.getStartOffset());
                     System.out.println("range:   endc="+range.getEndContainer());
                     System.out.println("range:   endo="+range.getEndOffset());
                     }
                     
                     ranged.insertNode(document.createTextNode("^"));
                     
                     result = toString(document);
                     System.out.println("After delete2: document="+result+":");
                     if (!result.equals(rangeDeleteResult[i])) {
                          System.out.println("Should be: document="+rangeDeleteResult[i]+":");
                          passed = false;
                          System.out.println("Test FAILED!");
                          System.out.println("*** Delete Ranges document Test["+i+"] FAILED!");
                     }
                  }
              }
                  
              }
              
         
          }
          catch (org.xml.sax.SAXParseException spe) {
              passed = false;
          }
          catch (org.xml.sax.SAXException se) {
              if (se.getException() != null)
                  se.getException().printStackTrace(System.err);
              else
                  se.printStackTrace(System.err);
              passed = false;
          }
          catch (Exception e) {
              e.printStackTrace(System.err);
              passed = false;
          }
          if (!passed) System.out.println("*** The "+arg+" Test FAILED! ***");
          
          return passed;
      }
      StringBuffer sb;
      boolean canonical = true;
      
      String toString(Node node) {
          sb = new StringBuffer();
          return print(node);
      
      }
     
     /** Prints the specified node, recursively. */
     public String print(Node node) {
  
        // is there anything to do?
        if ( node == null ) {
           return sb.toString();
        }
  
        int type = node.getNodeType();
        switch ( type ) {
           // print document
           case Node.DOCUMENT_NODE: {
                 return print(((Document)node).getDocumentElement());
                 //out.flush();
                 //break;
              }
  
              // print element with attributes
           case Node.ELEMENT_NODE: {
                 sb.append('<');
                 sb.append(node.getNodeName());
                 Attr attrs[] = sortAttributes(node.getAttributes());
                 for ( int i = 0; i < attrs.length; i++ ) {
                    Attr attr = attrs[i];
                    sb.append(' ');
                    sb.append(attr.getNodeName());
                    sb.append("=\"");
                    sb.append(normalize(attr.getNodeValue()));
                    sb.append('"');
                 }
                 sb.append('>');
                 NodeList children = node.getChildNodes();
                 if ( children != null ) {
                    int len = children.getLength();
                    for ( int i = 0; i < len; i++ ) {
                       print(children.item(i));
                    }
                 }
                 break;
              }
  
              // handle entity reference nodes
           case Node.ENTITY_REFERENCE_NODE: {
                 if ( canonical ) {
                    NodeList children = node.getChildNodes();
                    if ( children != null ) {
                       int len = children.getLength();
                       for ( int i = 0; i < len; i++ ) {
                          print(children.item(i));
                       }
                    }
                 } else {
                    sb.append('&');
                    sb.append(node.getNodeName());
                    sb.append(';');
                 }
                 break;
              }
  
              // print cdata sections
           case Node.CDATA_SECTION_NODE: {
                 if ( canonical ) {
                    sb.append(normalize(node.getNodeValue()));
                 } else {
                    sb.append("<![CDATA[");
                    sb.append(node.getNodeValue());
                    sb.append("]]>");
                 }
                 break;
              }
  
              // print text
           case Node.TEXT_NODE: {
                 sb.append(normalize(node.getNodeValue()));
                 break;
              }
  
              // print processing instruction
           case Node.PROCESSING_INSTRUCTION_NODE: {
                 sb.append("<?");
                 sb.append(node.getNodeName());
                 String data = node.getNodeValue();
                 if ( data != null && data.length() > 0 ) {
                    sb.append(' ');
                    sb.append(data);
                 }
                 sb.append("?>");
                 break;
              }
              // handle entity reference nodes
           case Node.DOCUMENT_FRAGMENT_NODE: {
              NodeList children = node.getChildNodes();
              if ( children != null ) {
                  int len = children.getLength();
                  for ( int i = 0; i < len; i++ ) {
                       print(children.item(i));
                  }
              }
                 break;
              }
        }
  
        if ( type == Node.ELEMENT_NODE ) {
           sb.append("</");
           sb.append(node.getNodeName());
           sb.append('>');
        }
  
        return sb.toString();
  
     } // print(Node)
  
     /** Returns a sorted list of attributes. */
     protected Attr[] sortAttributes(NamedNodeMap attrs) {
  
        int len = (attrs != null) ? attrs.getLength() : 0;
        Attr array[] = new Attr[len];
        for ( int i = 0; i < len; i++ ) {
           array[i] = (Attr)attrs.item(i);
        }
        for ( int i = 0; i < len - 1; i++ ) {
           String name  = array[i].getNodeName();
           int    index = i;
           for ( int j = i + 1; j < len; j++ ) {
              String curName = array[j].getNodeName();
              if ( curName.compareTo(name) < 0 ) {
                 name  = curName;
                 index = j;
              }
           }
           if ( index != i ) {
              Attr temp    = array[i];
              array[i]     = array[index];
              array[index] = temp;
           }
        }
  
        return (array);
  
     } // sortAttributes(NamedNodeMap):Attr[]
      
     /** Normalizes the given string. */
     protected String normalize(String s) {
        StringBuffer str = new StringBuffer();
  
        int len = (s != null) ? s.length() : 0;
        for ( int i = 0; i < len; i++ ) {
           char ch = s.charAt(i);
           switch ( ch ) {
              case '<': {
                    str.append("&lt;");
                    break;
                 }
              case '>': {
                    str.append("&gt;");
                    break;
                 }
              case '&': {
                    str.append("&amp;");
                    break;
                 }
              case '"': {
                    str.append("&quot;");
                    break;
                 }
              case '\r':
              case '\n': {
                    if ( canonical ) {
                       str.append("&#");
                       str.append(Integer.toString(ch));
                       str.append(';');
                       break;
                    }
                    // else, default append char
                 }
              default: {
                    str.append(ch);
                 }
           }
        }
  
        return (str.toString());
  
     } // normalize(String):String
     
      
  }