Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[stp-dev] patches for bug 168833

Hello all,

I have created two patches for bug 168833. See attached files.
Could someone help check and apply? Thank you in advance.

Frank from IONA

Below is the comment for the correction (also available in bugzilla):

Hi,

I implemented a DOM parser which is able to insert location information
into the DOM tree returned. Each element in the DOM tree is attached two
User Data named LineNumber and ColumnNumber respectively.

This parser also provides two static utility methods to directly retrieve
the line number and the column number of an element created by this parser.

Only standard JDK 1.5 libraries are used to realize this parser.

The SAXParser in library javax.xml.parsers accepts an object of class
org.xml.sax.helpers.DefaultHandler and calls the callback methods defined
in this class during the process of parsing an xml document.

SAXParser doesn't generate a DOM tree. It only parse and validate the xml
document. So a sub class of DefaultHandler is defined and in these callback
methods of the sub class, a DOM tree is created explicitly and separately.

In the test, two kinds of DOM trees are created: one by the standard JDK
parser, javax.xml.parsers.DocumentBuilder, the other by the parser in
question.
Nodes in these two trees from the same xml document are compared to
guarantee
that the DOM tree generated by the parser in question is correct.

The location information is also tested.

XML documents with and without names paces are both used to do the test.

Frank
### Eclipse Workspace Patch 1.0
#P org.eclipse.stp.sc.xmlvalidator.test
Index: src/resources/test_with_ns.xml
===================================================================
RCS file: src/resources/test_with_ns.xml
diff -N src/resources/test_with_ns.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/resources/test_with_ns.xml	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<wsdl:definitions name="HelloWorld" targetNamespace="http://objectweb.org/hello_world_rpclit"; 
+    xmlns="http://schemas.xmlsoap.org/wsdl/";
+    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"; 
+    xmlns:tns="http://objectweb.org/hello_world_rpclit";
+    xmlns:x1="http://objectweb.org/hello_world_rpclit/types";
+    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"; 
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema";>
+    <wsdl:types>
+        <schema targetNamespace="http://objectweb.org/hello_world_rpclit/types"; 
+            xmlns="http://www.w3.org/2001/XMLSchema"; elementFormDefault="qualified">
+            <complexType name="myComplexStruct">
+            <sequence>
+                <element name="elem1" type="xsd:string"/>
+                <element name="elem2" type="xsd:string"/>
+                <element name="elem3" type="xsd:int"/>
+            </sequence>
+            </complexType>
+        </schema>
+    </wsdl:types>
+    
+    <wsdl:message name="sayHiRequest"/>
+    
+    <wsdl:message name="sayHiResponse">
+        <wsdl:part type="xsd:string" name="out"/>
+    </wsdl:message>
+    
+    <wsdl:message name="greetMeRequest">
+        <wsdl:part type="xsd:string" name="in"/>
+    </wsdl:message>
+    
+    <wsdl:message name="greetMeResponse">
+        <wsdl:part type="xsd:string" name="out"/>
+    </wsdl:message>
+    
+    <wsdl:message name="sendReceiveDataRequest">
+        <wsdl:part type="x1:myComplexStruct" name="in"/>
+    </wsdl:message>
+    
+    <wsdl:message name="sendReceiveDataResponse">
+        <wsdl:part type="x1:myComplexStruct" name="out"/>
+    </wsdl:message>
+    
+    <wsdl:portType name="GreeterRPCLit">
+        <wsdl:operation name="sayHi">
+            <wsdl:input message="tns:sayHiRequest" name="sayHiRequest"/>
+            <wsdl:output message="tns:sayHiResponse" name="sayHiResponse"/>
+        </wsdl:operation>
+        <wsdl:operation name="greetMe">
+            <wsdl:input message="tns:greetMeRequest" name="greetMeRequest"/>
+            <wsdl:output message="tns:greetMeResponse" name="greetMeResponse"/>
+        </wsdl:operation>
+        <wsdl:operation name="sendReceiveData">
+            <wsdl:input message="tns:sendReceiveDataRequest" name="SendReceiveDataRequest"/>
+        <wsdl:output message="tns:sendReceiveDataResponse" name="SendReceiveDataResponse"/>
+        </wsdl:operation>
+    </wsdl:portType>
+    
+    <wsdl:binding name="Greeter_SOAPBinding_RPCLit" type="tns:GreeterRPCLit">
+    
+        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
+        
+        <wsdl:operation name="sayHi">
+            <soap:operation soapAction="" style="rpc"/>
+            <wsdl:input>
+                <soap:body namespace="http://objectweb.org/hello_world_rpclit"; use="literal"/>
+            </wsdl:input>
+            <wsdl:output>
+                <soap:body namespace="http://objectweb.org/hello_world_rpclit"; use="literal"/>
+            </wsdl:output>
+        </wsdl:operation>
+        
+        <wsdl:operation name="greetMe">
+            <soap:operation soapAction="" style="rpc"/>
+            <wsdl:input>
+                <soap:body namespace="http://objectweb.org/hello_world_rpclit"; use="literal"/>
+            </wsdl:input>
+            <wsdl:output>
+                <soap:body namespace="http://objectweb.org/hello_world_rpclit"; use="literal"/>
+            </wsdl:output>
+        </wsdl:operation>
+        
+        <wsdl:operation name="sendReceiveData">
+            <soap:operation soapAction="" style="rpc"/>
+               <wsdl:input>
+                   <soap:body namespace="http://objectweb.org/hello_world_rpclit"; use="literal"/>
+               </wsdl:input>
+               <wsdl:output>
+                   <soap:body namespace="http://objectweb.org/hello_world_rpclit"; use="literal"/>
+               </wsdl:output>   
+        </wsdl:operation>
+
+    </wsdl:binding>
+    
+    <wsdl:service name="SOAPServiceRPCLit">
+        <wsdl:port binding="tns:Greeter_SOAPBinding_RPCLit" name="SoapPortRPCLit">
+            <soap:address location="http://localhost:9000/SoapContext/SoapPort"/>
+        </wsdl:port>
+    </wsdl:service>
+</wsdl:definitions>
Index: src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParserTest.java
===================================================================
RCS file: src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParserTest.java
diff -N src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParserTest.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParserTest.java	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,176 @@
+package org.eclipse.stp.sc.xmlvalidator.rule.parser;
+
+import java.net.URL;
+import org.eclipse.core.runtime.Platform;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.*;
+import java.util.*;
+
+import junit.framework.TestCase;
+
+import org.eclipse.stp.sc.xmlvalidator.utils.XMLUtils;
+
+public class DomLocationParserTest extends TestCase {
+	
+	final static String TEST_XML_WITH_NS_FILE = "/src/resources/test_with_ns.xml";
+	final static String TEST_XML_WITHOUT_NS_FILE = "/src/resources/test_without_ns.xml";
+	
+	DocumentBuilder builder;
+	DomLocationParser parser;
+	
+	protected void setUp() throws Exception {
+		super.setUp();
+		parser = new DomLocationParser();
+		builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+	}
+	
+	protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+	
+	public void testParseWithNS() throws Exception {
+		URL baseURL = Platform.getBundle("org.eclipse.stp.sc.xmlvalidator.test").getEntry("/");
+		URL fileURL = new URL(baseURL, TEST_XML_WITH_NS_FILE);
+		Document doc1 = parser.parse(fileURL.openStream());
+		Document doc2 = builder.parse(fileURL.openStream());
+		assertTrue(XMLUtils.compareTrees(doc1, doc2) == true);
+	}
+
+	public void testParseWithoutNS() throws Exception {
+		URL baseURL = Platform.getBundle("org.eclipse.stp.sc.xmlvalidator.test").getEntry("/");
+		URL fileURL = new URL(baseURL, TEST_XML_WITHOUT_NS_FILE);
+		Document doc1 = parser.parse(fileURL.openStream());
+		Document doc2 = builder.parse(fileURL.openStream());
+		assertTrue(XMLUtils.compareTrees(doc1, doc2) == true);
+	}
+
+	public void testLocationWithNS() throws Exception {
+		URL baseURL = Platform.getBundle("org.eclipse.stp.sc.xmlvalidator.test").getEntry("/");
+		URL fileURL = new URL(baseURL, TEST_XML_WITH_NS_FILE);
+		Document doc = parser.parse(fileURL.openStream());
+		List<Element> elementList = XMLUtils.getElementList(doc);
+		assertTrue(elementList.size() == 52);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(0)) == 2);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(0)) == 1);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(1)) == 9);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(1)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(2)) == 10);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(2)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(3)) == 12);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(3)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(4)) == 13);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(4)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(5)) == 14);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(5)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(6)) == 15);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(6)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(7)) == 16);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(7)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(8)) == 22);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(8)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(9)) == 24);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(9)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(10)) == 25);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(10)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(11)) == 28);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(11)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(12)) == 29);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(12)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(13)) == 32);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(13)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(14)) == 33);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(14)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(15)) == 36);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(15)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(16)) == 37);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(16)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(17)) == 40);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(17)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(18)) == 41);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(18)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(19)) == 44);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(19)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(20)) == 45);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(20)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(21)) == 46);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(21)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(22)) == 47);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(22)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(23)) == 49);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(23)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(24)) == 50);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(24)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(25)) == 51);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(25)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(26)) == 53);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(26)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(27)) == 54);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(27)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(28)) == 55);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(28)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(29)) == 59);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(29)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(30)) == 61);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(30)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(31)) == 63);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(31)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(32)) == 64);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(32)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(33)) == 65);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(33)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(34)) == 66);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(34)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(35)) == 68);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(35)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(36)) == 69);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(36)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(37)) == 73);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(37)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(38)) == 74);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(38)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(39)) == 75);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(39)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(40)) == 76);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(40)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(41)) == 78);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(41)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(42)) == 79);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(42)) == 17);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(43)) == 83);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(43)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(44)) == 84);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(44)) == 13);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(45)) == 85);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(45)) == 16);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(46)) == 86);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(46)) == 20);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(47)) == 88);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(47)) == 16);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(48)) == 89);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(48)) == 20);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(49)) == 95);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(49)) == 5);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(50)) == 96);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(50)) == 9);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(51)) == 97);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(51)) == 13);
+	}
+
+	public void testLocationWithoutNS() throws Exception {
+		URL baseURL = Platform.getBundle("org.eclipse.stp.sc.xmlvalidator.test").getEntry("/");
+		URL fileURL = new URL(baseURL, TEST_XML_WITHOUT_NS_FILE);
+		Document doc = parser.parse(fileURL.openStream());
+		List<Element> elementList = XMLUtils.getElementList(doc);
+		assertTrue(elementList.size() == 4);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(0)) == 3);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(1)) == 4);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(2)) == 6);
+		assertTrue(DomLocationParser.getLineNumber(elementList.get(3)) == 10);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(0)) == 1);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(1)) == 5);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(2)) == 7);
+		assertTrue(DomLocationParser.getColumnNumber(elementList.get(3)) == 7);
+	}
+	
+}
Index: src/resources/test_without_ns.xml
===================================================================
RCS file: src/resources/test_without_ns.xml
diff -N src/resources/test_without_ns.xml
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/resources/test_without_ns.xml	1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+    <extension
+         point="org.eclipse.ui.views">
+      <category
+            name="Hello Category"
+            id="com.example.helloworld">
+      </category>
+      <view
+            name="Hello View"
+            icon="icons/sample.gif"
+            category="com.example.helloworld"
+            class="com.example.helloworld.HelloWorldView"
+            id="com.example.helloworld.HelloWorldView">
+      </view>
+   </extension>
+
+</plugin>
### Eclipse Workspace Patch 1.0
#P org.eclipse.stp.sc.xmlvalidator
Index: src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParser.java
===================================================================
RCS file: /cvsroot/stp/org.eclipse.stp.servicecreation/org.eclipse.stp.sc.xmlvalidator/src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParser.java,v
retrieving revision 1.2
diff -u -r1.2 DomLocationParser.java
--- src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParser.java	11 Dec 2006 03:49:53 -0000	1.2
+++ src/org/eclipse/stp/sc/xmlvalidator/rule/parser/DomLocationParser.java	22 Dec 2006 02:53:12 -0000
@@ -17,8 +17,28 @@
 *     IONA Technologies PLC - initial API and implementation
 
 *******************************************************************************/
+
 package org.eclipse.stp.sc.xmlvalidator.rule.parser;
 
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.*;
+
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Attributes;
+
+import java.io.*;
+import java.util.*;
+
+import org.eclipse.stp.common.logging.LoggingProxy;
+
 /**
  * The Dom model defined in JAXP does not container line number information associated with each node.
  * However, for the validator to work, we need to report the failed line number in the xml file to the caller.
@@ -26,9 +46,429 @@
  * error line in xml editor directly.
  * So I wrote this SAX based parser for the special need for our validator. 
  * The output is an DOM document with line number assigned with each node.
- * BTW, you can extend this parser to add more infermation to the dom during xml parsing if you need.   
+ * BTW, you can extend this parser to add more information to the dom during xml parsing if you need.   
  *
  */
 public class DomLocationParser {
 
+	/**
+	 * Name of the user data used to store the line number.
+	 */
+    public static final String USER_DATA_LINE_NUMBER = "LineNumber";
+    /**
+     * Name of the user data used to store the column number.
+     */
+    public static final String USER_DATA_COLUMN_NUMBER = "ColumnNumber";
+
+    /**
+     * Get the line number of an element in the orginal document.
+     * @param element an element contained in the tree parsed by this parser.
+     * @return the line number if it's defined, -1 otherwise.
+     */
+    public static int getLineNumber(Element element) {
+    	assert(element != null);
+    	Integer lineNumber = (Integer)element.getUserData(USER_DATA_LINE_NUMBER);
+    	if (lineNumber == null) return -1;
+    	return lineNumber.intValue();
+    }
+
+    /**
+     * Get the line number of an element in the orginal document.
+     * @param element an element contained in the tree parsed by this parser.
+     * @return the line number if it's defined, -1 otherwise.
+     */
+    public static int getColumnNumber(Element element) {
+    	assert(element != null);
+    	Integer columnNumber = (Integer)element.getUserData(USER_DATA_COLUMN_NUMBER);
+    	if (columnNumber == null) return -1;
+    	return columnNumber.intValue();
+    }
+
+    /**
+     * Parse an xml document and get a DOM tree with location information.
+     * @param is InputStream where the xml document is coming from.
+     * @return An instance of Document representing the DOM tree.
+     * @throws ParserConfigurationException
+     * @throws SAXException
+     * @throws IOException
+     */
+    public Document parse(InputStream is)
+                   throws ParserConfigurationException,
+                          SAXException,
+                          IOException {
+           SAXParserFactory saxFactory = SAXParserFactory.newInstance();
+           saxFactory.setNamespaceAware(true);
+           SAXParser saxParser = saxFactory.newSAXParser();
+           MyDefaultHandler dh = new MyDefaultHandler();
+           try {
+               saxParser.parse(is, dh);
+               Document ret = dom;
+               return ret;
+           }
+           finally {
+               dom = null;
+               dh.releaseResource();
+           }
+    }
+
+    /**
+     * Object used to store DOM representation of an xml document.
+     */
+    private Document dom = null;
+    /**
+     * Logging object for class DomLocationParser and its subclasses.
+     */
+    private static final LoggingProxy LOG = LoggingProxy.getlogger(DomLocationParser.class);
+
+    /**
+     * Inner class implementing callback interfaces so as to get the location information.
+     * @author ffan
+     *
+     */
+    private class MyDefaultHandler extends DefaultHandler {
+
+        /**
+         * Locator used by the underlying parser implementation.
+         * We need to save its reference to get the location info.
+         */
+        private Locator locator = null;
+
+        /**
+         * Cursor position (line number) when last callback method was invoked.
+         * When startElement() is called, basiclly it's the line number of current element.
+         * There's an exception for the first element - previous location is not available.
+         */
+        private int lastLineNumber = 1;
+
+        /**
+         * Cursor position (column number) when last callback method was invoked.
+         * When startElement() is called, basiclly it's the line number of current element.
+         * There's an exception for the first element - previous location is not available.
+         */
+        private int lastColumnNumber = 1;
+
+        /**
+         * Stack used to push and pop nodes - could be Document or Element.
+         */
+        LinkedList<Node> nodeStack = new LinkedList<Node>();
+        ArrayList<Attr> attrList = new ArrayList<Attr>();
+
+        /**
+         * Look backward to get the right location of the first element, if possible.
+         * Note that this is a best effort behaviour and there's no any guarantee.
+         */
+        private void adjustFirstElementLocation(char[] ch, int start, int length) {
+
+        	if (isFirstElementLocationAdjusted) return;
+        	if (!need2AdjustFirstElementLocation) return;
+
+        	String content = String.valueOf(ch, 0, start);
+            int pos = content.indexOf("<" + firstElement.getTagName());
+
+            if (pos == -1) {
+            	need2AdjustFirstElementLocation = false;
+            	return;
+            }
+
+            int lineNo = locator.getLineNumber();
+            for (int i = start + length - 1; i > pos; i--) {
+            	if (ch[i] == '\n') lineNo--;
+            }
+
+            int columnNo = 1;
+            for (int j = pos - 1; j > 0; j--) {
+            	if(ch[j] == '\n') break;
+            	columnNo++;
+            }
+
+            firstElement.setUserData(USER_DATA_LINE_NUMBER, Integer.valueOf(lineNo), null);
+            firstElement.setUserData(USER_DATA_COLUMN_NUMBER, Integer.valueOf(columnNo), null);
+            
+            isFirstElementLocationAdjusted = true;
+        }
+
+        /**
+         * The first element of an xml document, whose location need to be adjusted.
+         */
+        private Element firstElement = null;
+        /**
+         * If the location of the first element is adjusted already, don't adjust again.
+         */
+        private boolean isFirstElementLocationAdjusted = false;
+        /**
+         * If it's impossible to adjust location of the first element, don't adjust again.
+         */
+        private boolean need2AdjustFirstElementLocation = true;
+
+        /**
+         * Some ignorable characters (whitespace or CR/LF) are met during the parsing.
+         * Default handling, save current location as last location for the next callback.
+         */
+        public void characters(char[] ch,
+                               int start,
+                               int length)
+                        throws SAXException {
+        	LOG.debug("characters()");
+            super.characters(ch, start, length);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+            Node node = nodeStack.getLast().getLastChild(); 
+            if ( node instanceof Text && node != null) {
+            	Text text = (Text)node;
+            	text.replaceWholeText(text.getWholeText() + String.valueOf(ch, start, length));
+            } else {
+            	Text text = dom.createTextNode(String.valueOf(ch, start, length));
+            	nodeStack.getLast().appendChild(text);
+            }
+            adjustFirstElementLocation(ch, start, length);
+        }
+
+        /**
+         * Parsing of an xml document is to be finished.
+         * Remove the last node in the node stack - should be the only one in the stack. 
+         */
+        public void endDocument()
+                         throws SAXException {
+        	LOG.debug("endDocument()");
+            super.endDocument();
+            nodeStack.removeLast();
+            assert(nodeStack.isEmpty());
+        }
+
+        /**
+         * Parsing of an xml document is to be finished.
+         * Remove the last node in the node stack - should be the only one in the stack. 
+         */
+        public void endElement(String uri,
+                               String localName,
+                               String qName)
+                        throws SAXException {
+        	LOG.debug("endElement()");
+            super.endElement(uri, localName, qName);
+            nodeStack.removeLast();
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * End of the prefix mapping.
+         */
+        public void endPrefixMapping(String prefix)
+                              throws SAXException {
+        	LOG.debug("endPrefixMapping()");
+            super.endPrefixMapping(prefix);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * Ignorable error is met.
+         */
+        public void error(SAXParseException e)
+                   throws SAXException {
+        	LOG.debug("error()");
+            super.error(e);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * Some ignorable characters (whitespace or CR/LF) are met during the parsing.
+         * Default handling, save current location as last location for the next callback.
+         */
+        public void ignorableWhitespace(char[] ch,
+                                        int start,
+                                        int length)
+                                 throws SAXException {
+        	LOG.debug("ignorableWhitespace()");
+            super.ignorableWhitespace(ch, start, length);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+            adjustFirstElementLocation(ch, start, length);
+        }
+
+        /**
+         * Start of notation declaration.
+         */
+        public void notationDecl(String name,
+                                 String publicId,
+                                 String systemId)
+                          throws SAXException {
+        	LOG.debug("notationDecl()");
+            super.notationDecl(name, publicId, systemId);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * Processing of instructions.
+         */
+        public void processingInstruction(String target,
+                                          String data)
+                                   throws SAXException {
+        	LOG.debug("processingInstruction()");
+            super.processingInstruction(target, data);
+            dom.appendChild(dom.createProcessingInstruction(target, data));
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * External entity is met.
+         */
+        public InputSource resolveEntity(String publicId,
+                                         String systemId)
+                                  throws IOException,
+                                         SAXException {
+        	LOG.debug("resolveEntity()");
+            InputSource is = super.resolveEntity(publicId, systemId);
+            dom.setXmlStandalone(false);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+            return is;
+        }
+
+        /**
+         * Underlying parser implementation sets its locator.
+         * We save this locator to get the location of current cursor.
+         */
+        public void setDocumentLocator(Locator locator) {
+        	LOG.debug("setDocumentLocator()");
+            super.setDocumentLocator(locator);
+            this.locator = locator;
+        }
+
+        /**
+         * Some entity is skipped.
+         */
+        public void skippedEntity(String name)
+                           throws SAXException {
+        	LOG.debug("skippedEntity()");
+            super.skippedEntity(name);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+        
+        /**
+         * Start to parse an xml document.
+         */
+        public void startDocument()
+                           throws SAXException {
+        	LOG.debug("startDocument()");
+            super.startDocument();
+            try {
+                dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
+            }
+            catch (ParserConfigurationException e) {
+                throw new SAXException(e);
+            }
+             
+            nodeStack.add(dom);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        public void startElement(String uri,
+                                 String localName,
+                                 String qName,
+                                 Attributes attributes)
+                          throws SAXException {
+        	LOG.debug("startElement()");
+            super.startElement(uri, localName, qName, attributes);
+
+            Node parentNode = nodeStack.getLast();
+
+            Element element =  null;
+            if (uri == null || uri.equals("")) {
+                element = dom.createElement(qName);
+            } else {
+                element = dom.createElementNS(uri, qName);
+            }
+
+            if (firstElement == null) {
+            	firstElement = element;
+                element.setUserData(USER_DATA_LINE_NUMBER, Integer.valueOf(locator.getLineNumber()), null);
+                element.setUserData(USER_DATA_COLUMN_NUMBER, Integer.valueOf(locator.getColumnNumber()), null);
+            } else {
+            	element.setUserData(USER_DATA_LINE_NUMBER, Integer.valueOf(lastLineNumber), null);
+                element.setUserData(USER_DATA_COLUMN_NUMBER, Integer.valueOf(lastColumnNumber), null);
+            }
+
+        	for (int i = 0; i < attributes.getLength(); i++) {
+            	if (attributes.getURI(i) == null || attributes.getURI(i).equals("")) {
+                    element.setAttribute(attributes.getQName(i), attributes.getValue(i));
+            	} else {
+            		element.setAttributeNS(attributes.getURI(i), attributes.getQName(i), attributes.getValue(i));
+            	}
+            }
+
+        	Iterator<Attr> iterator = attrList.iterator();
+        	while(iterator.hasNext()) {
+        		element.setAttributeNodeNS(iterator.next());
+        		iterator.remove();
+        	}
+
+        	parentNode.appendChild(element);
+
+            nodeStack.add(element);
+
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * Start of prefix mapping.
+         */
+        public void startPrefixMapping(String prefix,
+                                       String uri)
+                                throws SAXException {
+        	LOG.debug("startPrefixMapping()");
+            super.startPrefixMapping(prefix, uri);
+            // location when starting prefix mapping is the same as
+            // location when starting element, so don't remember it
+            // lastLineNumber = locator.getLineNumber();
+            // lastColumnNumber = locator.getColumnNumber();
+            prefix = prefix.equals("") ? "xmlns" : "xmlns:" + prefix;
+            Attr attr = dom.createAttribute(prefix);
+            attr.setValue(uri);
+            attrList.add(attr);
+        }
+
+        /**
+         * Unparsed external entity declaration.
+         */
+        public void unparsedEntityDecl(String name,
+                                       String publicId,
+                                       String systemId,
+                                       String notationName)
+                                throws SAXException {
+        	LOG.debug("unparsedEntityDecl()");
+            super.unparsedEntityDecl(name, publicId, systemId, notationName);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * A warning is met.
+         */
+        public void warning(SAXParseException e)
+                     throws SAXException {
+        	LOG.debug("warning()");
+            super.warning(e);
+            lastLineNumber = locator.getLineNumber();
+            lastColumnNumber = locator.getColumnNumber();
+        }
+
+        /**
+         * Release all resources used in this handler.
+         *
+         */
+        private void releaseResource() {
+        	locator = null;
+            attrList.clear();
+            nodeStack.clear();
+            firstElement = null;
+        }
+    }
+
 }
Index: src/org/eclipse/stp/sc/xmlvalidator/utils/XMLUtils.java
===================================================================
RCS file: /cvsroot/stp/org.eclipse.stp.servicecreation/org.eclipse.stp.sc.xmlvalidator/src/org/eclipse/stp/sc/xmlvalidator/utils/XMLUtils.java,v
retrieving revision 1.1
diff -u -r1.1 XMLUtils.java
--- src/org/eclipse/stp/sc/xmlvalidator/utils/XMLUtils.java	4 Dec 2006 05:21:11 -0000	1.1
+++ src/org/eclipse/stp/sc/xmlvalidator/utils/XMLUtils.java	22 Dec 2006 02:53:12 -0000
@@ -1,9 +1,21 @@
 package org.eclipse.stp.sc.xmlvalidator.utils;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.w3c.dom.TypeInfo;
 
 public class XMLUtils {
 
@@ -13,4 +25,207 @@
 	    doc.normalize();
 	    return doc;
 	}
+	public static List<Element> getElementList(Document doc) {
+		assert(doc != null);
+		ArrayList<Element> elementList = new ArrayList<Element>();
+		NodeList nodeList = doc.getChildNodes();
+		if (nodeList != null) {
+			for (int i = 0; i < nodeList.getLength(); i ++) {
+				getElementList(nodeList.item(i), elementList);
+			}
+		}
+		return elementList;
+	}
+	public static boolean compareTrees(Document dom1, Document dom2) {
+		try {
+			compareDocuments(dom1, dom2);
+			NodeList nodeList1 = dom1.getChildNodes();
+			NodeList nodeList2 = dom2.getChildNodes();
+			assertTrue(nodeList1.getLength() == nodeList2.getLength());
+			compareNodeLists(nodeList1, nodeList2);
+		} catch (AssertionError e) {
+			return false;
+		}
+		return true;
+	}
+	private static void compareNodes(Node node1, Node node2) {
+		if (node1 == null || node2 == null) {
+			assertTrue(node1 == null && node2 == null);
+		} else {
+			compareStrings(node1.getBaseURI(), node2.getBaseURI());
+			// in case of namespace and qualified name, no way to set localName
+			//! compareStrings(node1.getLocalName(), node2.getLocalName());
+			// for the first element, the namespace URI are different:
+			// DomLocationParser: http://schemas.xmlsoap.org/wsdl/;
+			// DocumentBuilder (standard parser) from JDK: null.
+			//! compareStrings(node1.getNamespaceURI(), node2.getNamespaceURI());
+			compareStrings(node1.getNodeName(), node2.getNodeName());    
+			assertTrue(node1.getNodeType() == node2.getNodeType());    
+			compareStrings(node1.getNodeValue(), node2.getNodeValue());
+			// for the first element, the node prefix are different:
+			// DomLocationParser: wsdl; DocumentBuilder: null.
+			//! compareStrings(node1.getPrefix(), node2.getPrefix());
+			compareStrings(node1.getTextContent(), node2.getTextContent());
+		}
+	}
+	private static void compareElements(Element element1, Element element2) {
+		if (element1 == null || element2 == null) {
+			assertTrue(element1 == null && element2 == null);
+		} else {
+			// no enough data to get the schema type information 
+			//! compareTypeInfos(element1.getSchemaTypeInfo(), element2.getSchemaTypeInfo());
+			compareStrings(element1.getTagName(), element2.getTagName());
+			compareNodes(element1, element2);
+		}
+	}
+	private static void compareTypeInfos(TypeInfo typeInfo1, TypeInfo typeInfo2) {
+		if (typeInfo1 == null || typeInfo2 == null) {
+			assertTrue(typeInfo1 == null && typeInfo2 == null);
+		} else {
+			compareStrings(typeInfo1.getTypeName(), typeInfo2.getTypeName());
+			compareStrings(typeInfo1.getTypeNamespace(), typeInfo2.getTypeNamespace());
+		}
+	}
+	private static void compareDocuments(Document document1, Document document2) {
+		// no enough data to get the document type information
+		//! compareDocumentTypes(document1.getDoctype(), document2.getDoctype());
+		compareStrings(document1.getDocumentURI(), document2.getDocumentURI());
+		// no enough data to get the input encoding
+		//! compareStrings(document1.getInputEncoding(), document2.getInputEncoding());
+		assertTrue(document1.getStrictErrorChecking() == document2.getStrictErrorChecking());
+		// no enough data to get the XML encoding
+		//! compareStrings(document1.getXmlEncoding(), document2.getXmlEncoding());
+		assertTrue(document1.getXmlStandalone() == document2.getXmlStandalone());
+		compareStrings(document1.getXmlVersion(), document2.getXmlVersion());
+		compareNodes(document1, document2);
+	}
+	private static void compareDocumentTypes(DocumentType docType1, DocumentType docType2) {
+		if(docType1 == null || docType2 == null) {
+			assert(docType1 == null && docType2 == null);
+		} else {
+			// do something here
+		}
+	}
+	private static void compareStrings(String string1, String string2) {
+		if (string1 == null || string2 == null) {
+			assertTrue(string1 == string2);
+		} else {
+			assertTrue(string1.equals(string2));
+		}
+	}
+	private static void compareNodeLists(NodeList nodeList1, NodeList nodeList2) {
+		int i1 = 0, length1 = nodeList1 == null ? 0 : nodeList1.getLength();
+		int i2 = 0, length2 = nodeList2 == null ? 0 : nodeList2.getLength();
+
+		while ((i1 < length1) || (i2 < length2)) {
+			Node node1 = null;
+			Node node2 = null;
+
+			while (i1 < length1) {
+				Node node = nodeList1.item(i1++);
+				if (node instanceof Text) {
+					node1 = node;
+					break; 
+				}
+				if (node instanceof Element) {
+					node1 = node;
+					break; 
+				}
+				if (node instanceof ProcessingInstruction) {
+					node1 = node;
+					break; 
+				}
+			}
+			while (i2 < length2) {
+				Node node = nodeList2.item(i2++);
+				if (node instanceof Text) {
+					node2 = node;
+					break; 
+				}
+				if (node instanceof Element) {
+					node2 = node;
+					break; 
+				}
+				if (node instanceof ProcessingInstruction) {
+					node2 = node;
+					break; 
+				}
+			}
+			if ((node1 == null) || (node2 == null)) {
+				assertTrue((node1 == null) && (node2 == null));
+			} else {
+				if (node1 instanceof Text || node2 instanceof Text) {
+					assertTrue(node1 instanceof Text && node2 instanceof Text);
+					compareTexts((Text)node1, (Text)node2);
+				}
+				if (node1 instanceof Element || node2 instanceof Element) {
+					assertTrue(node1 instanceof Element && node2 instanceof Element);
+					compareElements((Element)node1, (Element)node2);
+					compareAttrLists(node1.getAttributes(), node2.getAttributes());
+					NodeList subList1 = node1.getChildNodes();
+					NodeList subList2 = node2.getChildNodes();
+					compareNodeLists(subList1, subList2);
+				}
+				if (node1 instanceof ProcessingInstruction || node2 instanceof ProcessingInstruction) {
+					assertTrue(node1 instanceof ProcessingInstruction && node2 instanceof ProcessingInstruction);
+					compareProcessingInstructions((ProcessingInstruction)node1, (ProcessingInstruction)node2);
+				}
+			}
+		}
+	}
+	private static void compareTexts(Text text1, Text text2) {
+		compareStrings(text1.getWholeText(), text2.getWholeText());
+		compareNodes(text1, text2);
+	}
+	private static void compareProcessingInstructions(ProcessingInstruction pi1, ProcessingInstruction pi2) {
+		if (pi1 == null || pi2 == null) {
+			assertTrue(pi1 == null || pi2 == null);
+		} else {
+			compareStrings(pi1.getTarget(), pi2.getTarget());
+			compareStrings(pi1.getData(), pi2.getData());
+			compareNodes(pi1, pi2);
+		}
+	}
+	private static void compareAttrs(Attr attr1, Attr attr2) {
+		if (attr1 == null || attr2 == null) {
+			assert(attr1 == null && attr2 == null);
+		} else {
+			compareStrings(attr1.getName(), attr2.getName());
+			// no enough data to get the type information
+			//! compareTypeInfos(attr1.getSchemaTypeInfo(), attr2.getSchemaTypeInfo());
+			assertTrue(attr1.getSpecified() == attr2.getSpecified());
+			compareStrings(attr1.getValue(), attr2.getValue());
+			assertTrue(attr1.isId() == attr2.isId());
+			compareNodes(attr1, attr2);
+		}
+	}
+	private static void compareAttrLists(NamedNodeMap attrList1, NamedNodeMap attrList2) {
+		int i1 = 0, length1 = attrList1 == null ? 0 : attrList1.getLength();
+		int i2 = 0, length2 = attrList2 == null ? 0 : attrList2.getLength();
+		assertTrue(length1 == length2);
+		while (i1 < length1 && i2 < length2) {
+			Node node1 = attrList1.item(i1++);
+			Node node2 = attrList2.item(i2++);
+			assertTrue(node1 instanceof Attr);
+			assertTrue(node2 instanceof Attr);
+			compareAttrs((Attr)node1, (Attr)node2);
+		}
+	}
+	private static void getElementList(Node node, List<Element> elementList) {
+		assert(node != null);
+		assert(elementList != null);
+		if(node instanceof Element) {
+			elementList.add((Element)node);
+			NodeList nodeList = node.getChildNodes();
+			if (nodeList == null) return;
+			for (int i = 0; i < nodeList.getLength(); i++) {
+				getElementList(nodeList.item(i), elementList);
+			}
+		}
+	}
+	private static void assertTrue(boolean condition) {
+		if(!condition) {
+			throw new AssertionError();
+		}
+	}
 }

Back to the top