1 11 package org.eclipse.pde.internal.core.text; 12 13 import java.io.StringReader ; 14 import java.util.ArrayList ; 15 import java.util.Stack ; 16 17 import org.eclipse.jface.text.BadLocationException; 18 import org.eclipse.jface.text.FindReplaceDocumentAdapter; 19 import org.eclipse.jface.text.IDocument; 20 import org.eclipse.jface.text.IRegion; 21 import org.eclipse.jface.text.Position; 22 import org.eclipse.jface.text.Region; 23 import org.eclipse.pde.internal.core.util.PDEXMLHelper; 24 import org.xml.sax.Attributes ; 25 import org.xml.sax.InputSource ; 26 import org.xml.sax.Locator ; 27 import org.xml.sax.SAXException ; 28 import org.xml.sax.SAXParseException ; 29 import org.xml.sax.helpers.DefaultHandler ; 30 31 public abstract class DocumentHandler extends DefaultHandler { 32 33 protected FindReplaceDocumentAdapter fFindReplaceAdapter; 34 protected Stack fDocumentNodeStack = new Stack (); 35 protected int fHighestOffset = 0; 36 private Locator fLocator; 37 private IDocumentNode fLastError; 38 private boolean fReconciling; 39 40 public DocumentHandler(boolean reconciling) { 41 fReconciling = reconciling; 42 } 43 44 47 public void startDocument() throws SAXException { 48 fDocumentNodeStack.clear(); 49 fHighestOffset = 0; 50 fLastError = null; 51 fFindReplaceAdapter = new FindReplaceDocumentAdapter(getDocument()); 52 } 53 54 57 public void startElement(String uri, String localName, String qName, 58 Attributes attributes) throws SAXException { 59 IDocumentNode parent = fDocumentNodeStack.isEmpty() ? null : (IDocumentNode)fDocumentNodeStack.peek(); 60 IDocumentNode node = getDocumentNode(qName, parent); 61 try { 62 int nodeOffset = getStartOffset(qName); 63 node.setOffset(nodeOffset); 64 IDocument doc = getDocument(); 65 int line = doc.getLineOfOffset(nodeOffset); 66 node.setLineIndent(node.getOffset() - doc.getLineOffset(line)); 67 for (int i = 0; i < attributes.getLength(); i++) { 69 String attName = attributes.getQName(i); 70 String attValue = attributes.getValue(i); 71 IDocumentAttribute attribute = getDocumentAttribute(attName, attValue, node); 72 if (attribute != null) { 73 IRegion region = getAttributeRegion(attName, attValue, nodeOffset); 74 if (region == null) { 75 attValue = PDEXMLHelper.getWritableString(attValue); 76 region = getAttributeRegion(attName, attValue, nodeOffset); 77 } 78 if (region != null) { 79 attribute.setNameOffset(region.getOffset()); 80 attribute.setNameLength(attName.length()); 81 attribute.setValueOffset(region.getOffset() + region.getLength() - 1 - attValue.length()); 82 attribute.setValueLength(attValue.length()); 83 } 84 node.setXMLAttribute(attribute); 85 } 86 } 87 removeOrphanAttributes(node); 88 } catch (BadLocationException e) { 89 } 90 if (parent != null && node != null && node.getParentNode() == null) { 91 if (fReconciling) { 92 int position = 0; 97 IDocumentNode[] children = parent.getChildNodes(); 98 for (; position < children.length; position++) { 99 if (children[position].getOffset() == -1) 100 break; 101 } 102 parent.addChildNode(node, position); 103 } else { 104 parent.addChildNode(node); 105 } 106 } 107 fDocumentNodeStack.push(node); 108 } 109 110 protected abstract IDocumentNode getDocumentNode(String name, IDocumentNode parent); 111 112 protected abstract IDocumentAttribute getDocumentAttribute(String name, String value, IDocumentNode parent); 113 114 private int getStartOffset(String elementName) throws BadLocationException { 115 int line = fLocator.getLineNumber(); 116 int col = fLocator.getColumnNumber(); 117 IDocument doc = getDocument(); 118 if (col < 0) 119 col = doc.getLineLength(line); 120 String text = doc.get(fHighestOffset + 1, doc.getLineOffset(line) - fHighestOffset - 1); 121 122 ArrayList commentPositions = new ArrayList (); 123 for (int idx = 0; idx < text.length();) { 124 idx = text.indexOf("<!--", idx); if (idx == -1) 126 break; 127 int end = text.indexOf("-->", idx); if (end == -1) 129 break; 130 131 commentPositions.add(new Position(idx, end - idx)); 132 idx = end + 1; 133 } 134 135 int idx = 0; 136 for (; idx < text.length(); idx += 1) { 137 idx = text.indexOf("<" + elementName, idx); if (idx == -1) 139 break; 140 boolean valid = true; 141 for (int i = 0; i < commentPositions.size(); i++) { 142 Position pos = (Position)commentPositions.get(i); 143 if (pos.includes(idx)) { 144 valid = false; 145 break; 146 } 147 } 148 if (valid) 149 break; 150 } 151 if (idx > -1) 152 fHighestOffset += idx + 1; 153 return fHighestOffset; 154 } 155 156 private int getElementLength(IDocumentNode node, int line, int column) throws BadLocationException { 157 int endIndex = node.getOffset(); 158 IDocument doc = getDocument(); 159 int start = Math.max(doc.getLineOffset(line), node.getOffset()); 160 column = doc.getLineLength(line); 161 String lineText= doc.get(start, column - start + doc.getLineOffset(line)); 162 163 int index = lineText.indexOf("</" + node.getXMLTagName() + ">"); if (index == -1) { 165 index= lineText.indexOf(">"); if (index == -1 ) { 167 endIndex = column; 168 } else { 169 endIndex = index + 1; 170 } 171 } else{ 172 endIndex = index + node.getXMLTagName().length() + 3; 173 } 174 return start + endIndex - node.getOffset(); 175 } 176 177 private IRegion getAttributeRegion(String name, String value, int offset) throws BadLocationException{ 178 IRegion nameRegion = fFindReplaceAdapter.find(offset, name+"\\s*=\\s*\"", true, true, false, true); if (nameRegion != null) { 180 if (getDocument().get(nameRegion.getOffset() + nameRegion.getLength(), value.length()).equals(value)) 181 return new Region(nameRegion.getOffset(), nameRegion.getLength() + value.length() + 1); 182 } 183 return null; 184 } 185 186 187 190 public void endElement(String uri, String localName, String qName) 191 throws SAXException { 192 if (fDocumentNodeStack.isEmpty()) 193 return; 194 195 IDocumentNode node = (IDocumentNode)fDocumentNodeStack.pop(); 196 try { 197 node.setLength(getElementLength(node, fLocator.getLineNumber() - 1, fLocator.getColumnNumber())); 198 setTextNodeOffset(node); 199 } catch (BadLocationException e) { 200 } 201 removeOrphanElements(node); 202 } 203 204 protected void setTextNodeOffset(IDocumentNode node) throws BadLocationException { 205 IDocumentTextNode textNode = node.getTextNode(); 206 if (textNode != null && textNode.getText() != null) { 207 if (textNode.getText().trim().length() == 0) { 208 node.removeTextNode(); 209 return; 210 } 211 IDocument doc = getDocument(); 212 String text = doc.get(node.getOffset(), node.getLength()); 213 int relativeStartOffset = text.indexOf('>') + 1; 215 int relativeEndOffset = text.lastIndexOf('<') - 1; 217 218 if ((relativeStartOffset < 0) || 219 (relativeStartOffset >= text.length())) { 220 return; 221 } else if ((relativeEndOffset < 0) || 222 (relativeEndOffset >= text.length())) { 223 return; 224 } 225 226 while (Character.isWhitespace(text.charAt(relativeStartOffset))) 228 relativeStartOffset += 1; 229 while (Character.isWhitespace(text.charAt(relativeEndOffset))) 230 relativeEndOffset -= 1; 231 232 textNode.setOffset(node.getOffset() + relativeStartOffset); 233 textNode.setLength(relativeEndOffset - relativeStartOffset + 1); 234 textNode.setText(textNode.getText().trim()); 235 } 236 } 237 238 241 public void fatalError(SAXParseException e) throws SAXException { 242 generateErrorElementHierarchy(); 243 } 244 245 248 private void generateErrorElementHierarchy() { 249 while (!fDocumentNodeStack.isEmpty()) { 250 IDocumentNode node = (IDocumentNode)fDocumentNodeStack.pop(); 251 node.setIsErrorNode(true); 252 removeOrphanAttributes(node); 253 removeOrphanElements(node); 254 if (fLastError == null) 255 fLastError = node; 256 } 257 } 258 259 262 public void error(SAXParseException e) throws SAXException { 263 generateErrorElementHierarchy(); 264 } 265 266 269 public void setDocumentLocator(Locator locator) { 270 fLocator = locator; 271 } 272 273 protected abstract IDocument getDocument(); 274 275 public InputSource resolveEntity(String publicId, String systemId) throws SAXException { 276 return new InputSource (new StringReader ("")); } 281 282 public IDocumentNode getLastErrorNode() { 283 return fLastError; 284 } 285 286 289 public void characters(char[] ch, int start, int length) throws SAXException { 290 if (!fReconciling || fDocumentNodeStack.isEmpty()) 291 return; 292 293 IDocumentNode parent = (IDocumentNode)fDocumentNodeStack.peek(); 294 StringBuffer buffer = new StringBuffer (); 295 buffer.append(ch, start, length); 296 IDocumentTextNode textNode = parent.getTextNode(); 297 if (textNode == null) { 298 if (buffer.toString().trim().length() > 0) { 299 textNode = new DocumentTextNode(); 300 textNode.setEnclosingElement(parent); 301 parent.addTextNode(textNode); 302 textNode.setText(buffer.toString().trim()); 303 } 304 } else { 305 textNode.setText(buffer.insert(0, textNode.getText()).toString()); 306 } 307 } 308 309 private void removeOrphanAttributes(IDocumentNode node) { 310 if (fReconciling) { 313 IDocumentAttribute[] attrs = node.getNodeAttributes(); 314 for (int i = 0; i < attrs.length; i++) { 315 if (attrs[i].getNameOffset() == -1) 316 node.removeDocumentAttribute(attrs[i]); 317 } 318 } 319 } 320 321 private void removeOrphanElements(IDocumentNode node) { 322 if (fReconciling) { 325 IDocumentNode[] children = node.getChildNodes(); 326 for (int i = 0; i < children.length; i++) { 327 if (children[i].getOffset() == -1) { 328 node.removeChildNode(children[i]); 329 } 330 } 331 } 332 } 333 334 protected boolean isReconciling() { 335 return fReconciling; 336 } 337 338 } 339 | Popular Tags |