| /******************************************************************************* |
| * Copyright (c) 2000, 2003 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.compare.examples.xml; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| |
| import org.apache.xerces.parsers.SAXParser; |
| import org.eclipse.compare.IEditableContent; |
| import org.eclipse.compare.IStreamContentAccessor; |
| import org.eclipse.compare.structuremergeviewer.Differencer; |
| import org.eclipse.compare.structuremergeviewer.IDiffContainer; |
| import org.eclipse.compare.structuremergeviewer.IStructureComparator; |
| import org.eclipse.compare.structuremergeviewer.IStructureCreator; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IRegion; |
| import org.eclipse.jface.text.Position; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| 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.helpers.LocatorImpl; |
| |
| /** |
| * This structure analyzer builds a parse tree of an XML document found in |
| * a <code>IByteContentAccessor</code> input by calling getStructure(Object) |
| */ |
| public class XMLStructureCreator implements IStructureCreator { |
| |
| protected static final boolean DEBUG_MODE = false; |
| |
| private XMLNode fcurrentParent; |
| private String fsignature; |
| private Document fdoc; |
| private boolean ignoreBodies = false; |
| //private String fName; |
| |
| public static final String DEFAULT_NAME = XMLCompareMessages.getString("XMLStructureCreator.pluginname"); //$NON-NLS-1$ |
| |
| private HashMap fIdMapsInternal; |
| private HashMap fIdMaps; |
| private HashMap fIdExtensionToName; |
| private HashMap fOrderedElementsInternal; |
| private HashMap fOrderedElements; |
| private HashMap idMap; |
| private ArrayList fOrdered; |
| |
| public static final String USE_UNORDERED = XMLCompareMessages.getString("XMLStructureCreator.unordered"); //$NON-NLS-1$ |
| public static final String USE_ORDERED = XMLCompareMessages.getString("XMLStructureCreator.ordered"); //$NON-NLS-1$ |
| public static final String DEFAULT_IDMAP= USE_ORDERED; |
| private String fIdMapToUse; |
| private boolean fUseIdMap; |
| |
| public static final String TYPE_ELEMENT = "element"; //$NON-NLS-1$ |
| public static final String TYPE_TEXT = "text"; //$NON-NLS-1$ |
| public static final String TYPE_ATTRIBUTE = "attribute"; //$NON-NLS-1$ |
| |
| //for signatures |
| public static final String ROOT_ID = "root"; //$NON-NLS-1$ |
| public static final char SIGN_SEPARATOR = '>';//'.' |
| public static final char SIGN_ENCLOSING = '$'; |
| public static final String SIGN_ELEMENT = SIGN_ENCLOSING + TYPE_ELEMENT + SIGN_ENCLOSING; |
| public static final String SIGN_TEXT = SIGN_ENCLOSING + TYPE_TEXT + SIGN_ENCLOSING; |
| public static final String SIGN_ATTRIBUTE = SIGN_ENCLOSING + TYPE_ATTRIBUTE + SIGN_ENCLOSING; |
| |
| public static final String IDMAP_UNORDERED = XMLCompareMessages.getString("XMLStructureCreator.idmap_unordered"); //$NON-NLS-1$ |
| |
| public static final char ID_SEPARATOR = '<'; |
| public static final char ID_TYPE_BODY = '<'; |
| |
| private static final String parserName = "org.apache.xerces.parsers.SAXParser"; //$NON-NLS-1$ |
| |
| private static boolean setValidation = false; //defaults |
| private static boolean setNameSpaces = true; |
| private static boolean setSchemaSupport = true; |
| private static boolean setSchemaFullSupport = false; |
| |
| private String fFileExt; |
| private boolean fFirstCall = true; |
| |
| private boolean fRemoveWhiteSpace; |
| |
| protected class XMLHandler extends DefaultHandler { |
| |
| protected Locator prevlocator; //previous locator |
| protected Locator locator; //current locator |
| |
| public void setDocumentLocator (Locator locator0) { |
| this.locator = locator0; |
| } |
| |
| // |
| // DocumentHandler methods |
| // |
| /** Processing instruction. */ |
| public void processingInstruction(String target, String data) { |
| |
| // System.out.println("target: " + target); |
| // System.out.println("data: " + data); |
| // System.out.print("<?"); |
| // System.out.print(target); |
| // if (data != null && data.length() > 0) { |
| // System.out.print(' '); |
| // System.out.print(data); |
| // } |
| // System.out.print("?>"); |
| // System.out.flush(); |
| prevlocator = new LocatorImpl(locator); |
| } // processingInstruction(String,String) |
| |
| /** Start document. */ |
| public void startDocument() { |
| |
| prevlocator = new LocatorImpl(locator); |
| |
| } // startDocument() |
| |
| /** Start element. */ |
| public void startElement(String uri, String local, String raw, |
| Attributes attrs) { |
| XMLNode currentElement; |
| |
| /* add root node for this element */ |
| |
| if (XMLStructureCreator.DEBUG_MODE) { |
| if (locator != null && prevlocator != null) { |
| System.out.println("prevlocator: line " + prevlocator.getLineNumber() + " column " + prevlocator.getColumnNumber() + " id " + prevlocator.getPublicId()); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| System.out.println("locator: line " + locator.getLineNumber() + " column " + locator.getColumnNumber() + " id " + locator.getPublicId()); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| } |
| |
| try { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Node where children field accessed: " + fcurrentParent.getId()); //$NON-NLS-1$ |
| XMLChildren currentParent = (XMLChildren) fcurrentParent; |
| currentParent.children++; |
| String elementId; |
| String elementName; |
| IRegion r= fdoc.getLineInformation(prevlocator.getLineNumber()-1); |
| |
| String parentSig= fsignature; |
| fsignature = fsignature + raw + SIGN_SEPARATOR; |
| |
| if ( isUseIdMap() && idMap.containsKey(fsignature) ) { |
| String attrName = (String)idMap.get(fsignature); |
| elementId = raw + new Character(ID_SEPARATOR) + attrs.getValue(attrName); |
| elementName = raw + " [" + attrName + "=" + attrs.getValue(attrName) + "]"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| } else { |
| if ( !currentParent.childElements.containsKey(raw) ) { |
| currentParent.childElements.put(raw,new Integer(1)); |
| } else { |
| currentParent.childElements.put(raw,new Integer(((Integer)currentParent.childElements.get(raw)).intValue()+1)); |
| } |
| elementId = raw+new Character(ID_SEPARATOR)+"["+currentParent.childElements.get(raw)+"]"; //$NON-NLS-2$ //$NON-NLS-1$ |
| elementName = MessageFormat.format("{0} [{1}]",new String[] {raw,currentParent.childElements.get(raw).toString()}); //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| currentElement = new XMLChildren(TYPE_ELEMENT,elementId,elementId,(fsignature+SIGN_ELEMENT),fdoc,r.getOffset()+prevlocator.getColumnNumber()-1,0); |
| currentElement.setName(elementName); |
| if ( isUseIdMap() && idMap.containsKey(fsignature)) |
| currentElement.setUsesIDMAP(true); |
| if (fOrdered != null && fOrdered.contains(parentSig)) |
| currentElement.setIsOrderedChild(true); |
| |
| fcurrentParent.addChild(currentElement); |
| currentElement.setParent(fcurrentParent); |
| fcurrentParent = currentElement; |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("\nAdded Element " + raw + " with offset " + r.getOffset()); //$NON-NLS-2$ //$NON-NLS-1$ |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("fcurrentParent1: " + fcurrentParent.getId()); //$NON-NLS-1$ |
| |
| if (attrs != null) { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("attrs != null, fcurrentParent is " + fcurrentParent.getId()); //$NON-NLS-1$ |
| //attrs = sortAttributes(attrs); |
| int len = attrs.getLength(); |
| int element_lines_length_size; |
| int[] element_lines_length; |
| int column_offset; |
| String element_string; |
| if (fcurrentParent.getParent().getId().equals(ROOT_ID)) { |
| element_lines_length_size = locator.getLineNumber()-prevlocator.getLineNumber(); |
| element_lines_length = new int[element_lines_length_size]; |
| column_offset = 0; |
| element_string = ""; //$NON-NLS-1$ |
| for (int i_ell=0; i_ell<element_lines_length.length; i_ell++) { |
| IRegion attr_r = fdoc.getLineInformation(i_ell+prevlocator.getLineNumber()); |
| element_lines_length[i_ell] = fdoc.get(attr_r.getOffset(), attr_r.getLength()).length()+1; |
| element_string = element_string + fdoc.get(attr_r.getOffset(), attr_r.getLength()) + " "; //$NON-NLS-1$ |
| } |
| } else { |
| element_lines_length_size = locator.getLineNumber()-prevlocator.getLineNumber()+1; |
| //if (element_lines_length_size < 1) element_lines_length_size = 1; |
| element_lines_length = new int[element_lines_length_size]; |
| IRegion first_line = fdoc.getLineInformation(prevlocator.getLineNumber()-1); |
| column_offset = prevlocator.getColumnNumber()-1; |
| int first_line_relevant_offset = first_line.getOffset()+column_offset; |
| int first_line_relevant_length = first_line.getLength()-column_offset; |
| element_string = fdoc.get(first_line_relevant_offset, first_line_relevant_length) + " "; //$NON-NLS-1$ |
| element_lines_length[0] = element_string.length(); |
| for (int i_ell=1; i_ell<element_lines_length.length; i_ell++) { |
| IRegion attr_r = fdoc.getLineInformation(i_ell+prevlocator.getLineNumber()-1); |
| element_lines_length[i_ell] = fdoc.get(attr_r.getOffset(), attr_r.getLength()).length()+1; |
| element_string = element_string + fdoc.get(attr_r.getOffset(), attr_r.getLength()) + " "; //$NON-NLS-1$ |
| } |
| } |
| |
| for (int i_attr = 0; i_attr < len; i_attr++) { |
| String attr_name = attrs.getQName(i_attr); |
| String attr_value = attrs.getValue(i_attr); |
| |
| /* find range of attribute in doc; manually parses the line */ |
| boolean found = false; |
| int first_quotes = -1; |
| int second_quotes = -1; |
| int id_index = -1; |
| while (!found) { |
| first_quotes = element_string.indexOf("\"",second_quotes+1); //$NON-NLS-1$ |
| second_quotes = element_string.indexOf("\"",first_quotes+1); //$NON-NLS-1$ |
| String value; |
| try { |
| value = element_string.substring(first_quotes+1,second_quotes); |
| } catch (Exception e) { |
| value = ""; //$NON-NLS-1$ |
| } |
| if (value.equals("")) //$NON-NLS-1$ |
| found = true; |
| else if (value.equals(attr_value)) { |
| id_index = element_string.lastIndexOf(attr_name,first_quotes-1); |
| boolean wrong = false; |
| boolean found_equal = false; |
| for (int i_char=id_index+attr_name.length(); i_char<first_quotes && !wrong; i_char++) { |
| if (element_string.charAt(i_char) == '=') |
| if (!found_equal) |
| found_equal = true; |
| else |
| wrong = true; |
| else if (!Character.isWhitespace(element_string.charAt(i_char))) |
| wrong = true; |
| } |
| if (!wrong) found = true; |
| } |
| } |
| //id_index has one char missing for every line (the final cr) |
| int line_of_index = 0; |
| for (line_of_index = 0; id_index > element_lines_length[line_of_index]-1; line_of_index++) |
| id_index -= (element_lines_length[line_of_index]); |
| if (line_of_index == 0) id_index += column_offset; |
| if (fcurrentParent.getParent().getId().equals(ROOT_ID)) |
| line_of_index += prevlocator.getLineNumber(); |
| else |
| line_of_index += prevlocator.getLineNumber()-1; |
| //index at line line_of_index, line offset id_index |
| int line_of_end_of_value = 0; |
| int end_of_value_index = second_quotes; |
| for (line_of_end_of_value = 0; end_of_value_index > element_lines_length[line_of_end_of_value]-1; line_of_end_of_value++) |
| end_of_value_index -= (element_lines_length[line_of_end_of_value]); |
| if (line_of_end_of_value == 0) end_of_value_index += column_offset; |
| if (fcurrentParent.getParent().getId().equals(ROOT_ID)) |
| line_of_end_of_value += prevlocator.getLineNumber(); |
| else |
| line_of_end_of_value += prevlocator.getLineNumber()-1; |
| //end of value at line line_of_end_of_value, line offset end_of_value_index |
| |
| int attr_start_doc_offset = fdoc.getLineInformation(line_of_index).getOffset()+id_index; |
| //int attr_length_doc_offset = fdoc.getLineInformation(line_of_value).getOffset()+value_index+attr_value.length()+1+(line_of_end_of_value-line_of_index) - attr_start_doc_offset; |
| int attr_length_doc_offset = fdoc.getLineInformation(line_of_end_of_value).getOffset()+end_of_value_index +1 - attr_start_doc_offset; |
| currentElement = new XMLNode(TYPE_ATTRIBUTE,attr_name,attr_value,(fsignature+attr_name+SIGN_SEPARATOR+SIGN_ATTRIBUTE),fdoc,attr_start_doc_offset,attr_length_doc_offset); |
| currentElement.setName(attr_name); |
| fcurrentParent.addChild(currentElement); |
| currentElement.setParent(fcurrentParent); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("added attribute " + currentElement.getId() + " with value >" + currentElement.getValue() + "<" + " to element " + fcurrentParent.getId() + " which has parent " + fcurrentParent.getParent().getId()); //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| } |
| } catch (BadLocationException ex) { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("BadLocationException in startElement(...) " + ex); //$NON-NLS-1$ |
| currentElement = new XMLChildren(TYPE_ELEMENT,raw+"_("+((XMLChildren)fcurrentParent).children+")",raw+"_("+((XMLChildren)fcurrentParent).children+")",(fsignature+SIGN_ELEMENT),fdoc,0,0); //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("At the end of startElement(...), fcurrentParent is " + fcurrentParent.getId()); //$NON-NLS-1$ |
| prevlocator = new LocatorImpl(locator); |
| } // startElement(String,String,String,Attributes) |
| |
| /** Characters. */ |
| public void characters(char ch[], int start, int length) { |
| if (!ignoreBodies) { |
| // String chars = (new String(ch, start, length)).trim(); |
| String chars= new String(ch, start, length); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("characters: >" + chars + "<"); //$NON-NLS-2$ //$NON-NLS-1$ |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Body Location: line " + locator.getLineNumber() + " column " + locator.getColumnNumber()); //$NON-NLS-2$ //$NON-NLS-1$ |
| |
| //if text contains only white space, it will be ignored. |
| if (!trimWhiteSpace(chars).equals("")) { //$NON-NLS-1$ |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Adding body"); //$NON-NLS-1$ |
| try { |
| IRegion r= fdoc.getLineInformation(locator.getLineNumber()-1); |
| //location returns the END of the characters |
| //offset of BEGINNING of characters: |
| int offset = r.getOffset()+locator.getColumnNumber()-1-length; |
| fcurrentParent.bodies++; |
| String body_value = new String(ch, start, length); |
| if (fRemoveWhiteSpace) { |
| body_value= removeWhiteSpace(body_value); |
| } |
| XMLNode bodynode = new XMLNode(TYPE_TEXT,"body_("+fcurrentParent.bodies+")",body_value,(fsignature+SIGN_TEXT),fdoc,offset,length); //$NON-NLS-2$ //$NON-NLS-1$ |
| bodynode.setName(MessageFormat.format("{0} ({1})",new String[] {XMLCompareMessages.getString("XMLStructureCreator.body"),Integer.toString(fcurrentParent.bodies)})); //$NON-NLS-2$ //$NON-NLS-1$ |
| fcurrentParent.addChild(bodynode); |
| bodynode.setParent(fcurrentParent); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Created body " + fcurrentParent.bodies //$NON-NLS-1$ |
| + " with offset " + offset + " and length " + length //$NON-NLS-2$ //$NON-NLS-1$ |
| + " with parent " + bodynode.getParent().getId()); //$NON-NLS-1$ |
| //bodies as id attributes |
| String popsig = fcurrentParent.getParent().getSignature(); //signature of parent of parent |
| popsig = popsig.substring(0,popsig.lastIndexOf(SIGN_ELEMENT)); |
| if (isUseIdMap() && fcurrentParent.bodies == 1 && idMap.containsKey(popsig)) { |
| String pid= fcurrentParent.getId();//id of parent |
| String pelementname= pid.substring(0,pid.indexOf("<"));//name of parent element //$NON-NLS-1$ |
| if ( ((String)idMap.get(popsig)).equals(ID_TYPE_BODY+pelementname) ) { |
| XMLNode pop= fcurrentParent.getParent(); |
| String popid= pop.getId(); |
| String popelementname= popid.substring(0,popid.indexOf("<")); //$NON-NLS-1$ |
| pop.setId(popelementname + "<" + body_value); //$NON-NLS-1$ |
| pop.setOrigId(popelementname + "<" + body_value); //$NON-NLS-1$ |
| pop.setName(MessageFormat.format("{0} [{1}={2}]",new String[] {popelementname, pelementname, body_value})); //$NON-NLS-1$ |
| pop.setUsesIDMAP(true); |
| } |
| } |
| } catch (BadLocationException ex) { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("BadLocationException in characters(...) " + ex); //$NON-NLS-1$ |
| fcurrentParent.addChild(new XMLNode(TYPE_TEXT,"body_("+fcurrentParent.bodies+")",new String(ch, start, length),(fsignature+SIGN_TEXT),fdoc,0,0)); //$NON-NLS-2$ //$NON-NLS-1$ |
| } |
| } |
| } |
| prevlocator = new LocatorImpl(locator); |
| } // characters(char[],int,int); |
| |
| /** Ignorable whitespace. */ |
| public void ignorableWhitespace(char ch[], int start, int length) { |
| // |
| //// characters(ch, start, length); |
| //// System.out.flush(); |
| // |
| prevlocator = new LocatorImpl(locator); |
| } // ignorableWhitespace(char[],int,int); |
| |
| /** End element. */ |
| public void endElement(String uri, String local, String raw) { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("\nExiting element " + fcurrentParent.getId()); //$NON-NLS-1$ |
| |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("prevlocator: line " + prevlocator.getLineNumber() + " column " + prevlocator.getColumnNumber() + " id " + prevlocator.getPublicId()); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("locator: line " + locator.getLineNumber() + " column " + locator.getColumnNumber() + " id " + locator.getPublicId()); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| |
| |
| if (fcurrentParent.getParent() != null) { |
| try { |
| IRegion r2= fdoc.getLineInformation(locator.getLineNumber()-1); |
| Position pos = fcurrentParent.getRange(); |
| |
| int elem_length = r2.getOffset()+locator.getColumnNumber()-1 - pos.getOffset();//length of element from start tag to end tag |
| fcurrentParent.setLength(elem_length); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("pos.getOffset: " + pos.getOffset() + " elem_length: " + elem_length); //$NON-NLS-2$ //$NON-NLS-1$ |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("fdoc.get(pos.getOffset()+elem_length-5,4): >" + fdoc.get(pos.getOffset()+elem_length-5,4) + "<"); //$NON-NLS-2$ //$NON-NLS-1$ |
| //if (fdoc.get(pos.getOffset()+elem_length-2,1) != ">") elem_length-=1; |
| try { |
| fcurrentParent.setValue(fdoc.get(pos.getOffset(),elem_length)); |
| } catch (BadLocationException ex) { |
| try { |
| fcurrentParent.setValue(fdoc.get(pos.getOffset(),elem_length-1)); |
| } catch (BadLocationException ex2) { |
| if (XMLStructureCreator.DEBUG_MODE) { |
| System.out.println("BadLocationException in endElement(...) while attempting fcurrentParent.setValue(...): " + ex); //$NON-NLS-1$ |
| System.out.println("Attempt to correct BadLocationException failed: " + ex2); //$NON-NLS-1$ |
| } |
| } |
| } |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Value of " + fcurrentParent.getId() + " is >" + fcurrentParent.getValue() + "<"); //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$ |
| |
| //going from ending element to parent element |
| fcurrentParent = fcurrentParent.getParent(); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("fcurrentParent = fcurrentParent.getParent();"); //$NON-NLS-1$ |
| } catch (BadLocationException ex) { |
| if (XMLStructureCreator.DEBUG_MODE) { |
| System.out.println("BadLocationException in endElement(...): " + ex); //$NON-NLS-1$ |
| System.out.println("fcurrentParent.getId(): " + fcurrentParent.getId()); //$NON-NLS-1$ |
| } |
| } |
| } else { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Error: Cannot reach Parent of Parent"); //$NON-NLS-1$ |
| } |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("fcurrentParent is now " + fcurrentParent.getId()); //$NON-NLS-1$ |
| |
| prevlocator = new LocatorImpl(locator); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Signature before cutting: " + fsignature); //$NON-NLS-1$ |
| int ssi = fsignature.lastIndexOf(SIGN_SEPARATOR);//fsignature separator index |
| ssi = fsignature.lastIndexOf(SIGN_SEPARATOR,ssi-1);//second-last ".", e.g. in root.a.b. to obtain root.a. |
| fsignature = fsignature.substring(0,ssi+1); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Signature after cutting: " + fsignature); //$NON-NLS-1$ |
| } // endElement(String) |
| |
| // |
| // ErrorHandler methods |
| // |
| |
| /** Warning. */ |
| public void warning(SAXParseException ex) { |
| System.err.println("[Warning] "+ //$NON-NLS-1$ |
| getLocationString(ex)+": "+ //$NON-NLS-1$ |
| ex.getMessage()); |
| } |
| |
| /** Error. */ |
| public void error(SAXParseException ex) { |
| System.err.println("[Error] "+ //$NON-NLS-1$ |
| getLocationString(ex)+": "+ //$NON-NLS-1$ |
| ex.getMessage()); |
| } |
| |
| /** Fatal error. */ |
| public void fatalError(SAXParseException ex) throws SAXException { |
| System.err.println("[Fatal Error] "+ //$NON-NLS-1$ |
| getLocationString(ex)+": "+ //$NON-NLS-1$ |
| ex.getMessage()); |
| //System.out.println(ex); |
| //throw ex; |
| } |
| |
| /** Returns a string of the location. */ |
| private String getLocationString(SAXParseException ex) { |
| StringBuffer str = new StringBuffer(); |
| |
| String systemId = ex.getSystemId(); |
| if (systemId != null) { |
| int index = systemId.lastIndexOf('/'); |
| if (index != -1) |
| systemId = systemId.substring(index + 1); |
| str.append(systemId); |
| } |
| str.append(':'); |
| str.append(ex.getLineNumber()); |
| str.append(':'); |
| str.append(ex.getColumnNumber()); |
| |
| return str.toString(); |
| |
| } // getLocationString(SAXParseException):String |
| |
| } |
| |
| public XMLStructureCreator() { |
| //set default idmap |
| fIdMapToUse= DEFAULT_IDMAP; |
| fUseIdMap= false; |
| XMLPlugin plugin= XMLPlugin.getDefault(); |
| //if statement required for tests |
| if (plugin != null) { |
| fIdMaps = plugin.getIdMaps(); |
| fIdMapsInternal = plugin.getIdMapsInternal(); |
| fIdExtensionToName = plugin.getIdExtensionToName(); |
| fOrderedElements= plugin.getOrderedElements(); |
| fOrderedElementsInternal= plugin.getOrderedElementsInternal(); |
| } |
| fRemoveWhiteSpace= false; |
| } |
| |
| // public void setNameScheme(String idmap_name) { |
| // fName = MessageFormat.format("{0} ({1})", new String[] {DEFAULT_NAME,idmap_name}); //$NON-NLS-1$ |
| // } |
| // |
| /** |
| * This title will be shown in the title bar of the structure compare pane. |
| */ |
| public String getName() { |
| return DEFAULT_NAME; |
| } |
| |
| /** |
| * Set File extension of the parsed file. This extension will be used to choose an Id Map scheme. |
| */ |
| public void setFileExtension(String ext) { |
| fFileExt= ext; |
| } |
| |
| /** |
| * Initialize the Id Mappings for the Id Mapping Scheme and the Ordered Elements |
| * This method must be called before getStructure(Object) is called on the two/three inputs of the compare |
| */ |
| public void initIdMaps() { |
| if (fFirstCall && fFileExt != null) { |
| fFirstCall = false; |
| String fileExtLower= fFileExt.toLowerCase(); |
| if (fIdExtensionToName.containsKey(fileExtLower)) |
| setIdMap((String)fIdExtensionToName.get(fileExtLower)); |
| } |
| |
| setUseIdMap(); |
| fOrdered= null; |
| if (!isUseIdMap()) |
| idMap = null; |
| else if (fIdMaps.containsKey(fIdMapToUse)) { |
| idMap = (HashMap) fIdMaps.get(fIdMapToUse); |
| } else if (fIdMapsInternal.containsKey(fIdMapToUse)) { |
| idMap = (HashMap) fIdMapsInternal.get(fIdMapToUse); |
| } |
| |
| if (fOrderedElements != null) |
| fOrdered= (ArrayList) fOrderedElements.get(fIdMapToUse); |
| if (fOrdered == null && fOrderedElementsInternal != null) |
| fOrdered= (ArrayList) fOrderedElementsInternal.get(fIdMapToUse); |
| } |
| |
| /** |
| * Returns the XML parse tree of the input. |
| */ |
| public IStructureComparator getStructure(Object input) { |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("Starting parse"); //$NON-NLS-1$ |
| |
| if (!(input instanceof IStreamContentAccessor)) |
| return null; |
| |
| IStreamContentAccessor sca= (IStreamContentAccessor) input; |
| |
| try { |
| |
| //Input parsed with parser.parse(new InputSource(sca.getContents)); |
| String contents= readString(sca.getContents()); |
| if (contents == null) |
| contents= ""; //$NON-NLS-1$ |
| |
| fdoc= new Document(contents); |
| fsignature = ROOT_ID + SIGN_SEPARATOR; |
| XMLChildren root= new XMLChildren(TYPE_ELEMENT,ROOT_ID, "",(fsignature+SIGN_ELEMENT), fdoc, 0, fdoc.getLength()); //$NON-NLS-1$ |
| fcurrentParent = root; |
| |
| XMLHandler handler = new XMLHandler(); |
| |
| try { |
| SAXParser parser = (SAXParser)Class.forName(parserName).newInstance(); |
| |
| parser.setFeature( "http://xml.org/sax/features/validation",setValidation); //$NON-NLS-1$ |
| parser.setFeature( "http://xml.org/sax/features/namespaces",setNameSpaces ); //$NON-NLS-1$ |
| parser.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$ |
| parser.setFeature( "http://apache.org/xml/features/validation/schema",setSchemaSupport ); //$NON-NLS-1$ |
| parser.setFeature( "http://apache.org/xml/features/validation/schema-full-checking",setSchemaFullSupport ); //$NON-NLS-1$ |
| |
| parser.setContentHandler(handler); |
| parser.setErrorHandler(handler); |
| |
| parser.parse(new InputSource(sca.getContents())); |
| if (XMLStructureCreator.DEBUG_MODE) System.out.println("End of parse"); //$NON-NLS-1$ |
| } catch (SAXParseException e) { |
| XMLPlugin.log(e); |
| return null; |
| } catch (Exception e) { |
| // MessageDialog.openError(XMLPlugin.getActiveWorkbenchShell(),"Error in XML parser","An error occured in the XML parser.\nNo structured compare can be shown"); |
| XMLPlugin.log(e); |
| return null; |
| } |
| |
| return root; |
| } catch (CoreException ex) { |
| XMLPlugin.log(ex); |
| } |
| return null; |
| } |
| |
| public boolean canSave() { |
| return true; |
| } |
| |
| public boolean canRewriteTree() { |
| return false; |
| } |
| |
| public void rewriteTree(Differencer differencer, IDiffContainer root) { |
| } |
| |
| public void save(IStructureComparator structure, Object input) { |
| if (input instanceof IEditableContent && structure instanceof XMLNode) { |
| IDocument doc= ((XMLNode)structure).getDocument(); |
| IEditableContent bca= (IEditableContent) input; |
| String c= doc.get(); |
| bca.setContent(c.getBytes()); |
| } |
| } |
| |
| public String getContents(Object node, boolean ignoreWhitespace) { |
| if (node instanceof XMLNode) { |
| String s= ((XMLNode)node).getValue(); |
| if (ignoreWhitespace) |
| s= s.trim(); |
| return s; |
| } |
| return null; |
| } |
| |
| public IStructureComparator locate(Object path, Object source) { |
| return null; |
| } |
| |
| /** |
| * Returns null if an error occurred. |
| */ |
| static String readString(InputStream is) { |
| if (is == null) |
| return null; |
| BufferedReader reader= null; |
| try { |
| StringBuffer buffer= new StringBuffer(); |
| char[] part= new char[2048]; |
| int read= 0; |
| reader= new BufferedReader(new InputStreamReader(is)); |
| |
| while ((read= reader.read(part)) != -1) |
| buffer.append(part, 0, read); |
| |
| return buffer.toString(); |
| |
| } catch (IOException ex) { |
| } finally { |
| if (reader != null) { |
| try { |
| reader.close(); |
| } catch (IOException ex) { |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** Returns a sorted list of attributes. */ |
| /* Taken from SAX2Writer sample of xerces */ |
| protected Attributes sortAttributes(Attributes attrs) { |
| |
| AttributesImpl attributes = new AttributesImpl(); |
| int len = (attrs != null) ? attrs.getLength() : 0; |
| for (int i = 0; i < len; i++) { |
| String name = attrs.getQName(i); |
| int count = attributes.getLength(); |
| int j = 0; |
| while (j < count) { |
| if (name.compareTo(attributes.getQName(j)) < 0) { |
| break; |
| } |
| j++; |
| } |
| attributes.insertAttributeAt(j, name, attrs.getType(i), |
| attrs.getValue(i)); |
| } |
| |
| return attributes; |
| |
| } // sortAttributes(AttributeList):AttributeList |
| |
| public void setIdMap(String idmap_name) { |
| fIdMapToUse= idmap_name; |
| } |
| |
| /** Returns the name of the IdMap Scheme that will be used to set ids. |
| */ |
| public String getIdMap() { |
| return fIdMapToUse; |
| } |
| |
| public void setUseIdMap() { |
| if (fIdMaps != null && fIdMapsInternal != null) |
| fUseIdMap= fIdMaps.containsKey(fIdMapToUse) || fIdMapsInternal.containsKey(fIdMapToUse); |
| } |
| |
| public boolean isUseIdMap() { |
| return fUseIdMap; |
| } |
| |
| public void updateIdMaps() { |
| fIdMaps = XMLPlugin.getDefault().getIdMaps(); |
| fOrderedElements= XMLPlugin.getDefault().getOrderedElements(); |
| } |
| |
| protected boolean isWhiteSpace(char c) { |
| return c == '\t' || c == '\n' || c == '\r' || c == ' '; |
| } |
| |
| protected String removeWhiteSpace(String str) { |
| str= trimWhiteSpace(str); |
| StringBuffer retStr= new StringBuffer(); |
| int start= 0, end= 0; |
| outer_while: |
| while (true) { |
| while ( end < str.length() && !isWhiteSpace(str.charAt(end)) ) { end++; } |
| if (end > str.length()) break outer_while; |
| if ( start != 0) retStr.append(' '); |
| retStr.append(str.substring(start, end)); |
| end++; |
| while ( end < str.length() && isWhiteSpace(str.charAt(end)) ) { end++; } |
| start= end; |
| } |
| return retStr.toString(); |
| } |
| |
| protected String trimWhiteSpace(String str) { |
| int start=0, end= str.length()-1; |
| while (start < str.length() && isWhiteSpace(str.charAt(start))) { start++; } |
| if ( start == str.length() ) |
| return ""; //$NON-NLS-1$ |
| while (end >= 0 && isWhiteSpace(str.charAt(end))) { end--; } |
| return str.substring(start, end+1); |
| } |
| |
| public void setRemoveWhiteSpace(boolean removeWhiteSpace) { |
| fRemoveWhiteSpace= removeWhiteSpace; |
| } |
| |
| public boolean getRemoveWhiteSpace() { |
| return fRemoveWhiteSpace; |
| } |
| } |