1 23 24 package org.enhydra.xml.xmlc.html.parsers.swing; 25 26 import java.io.IOException ; 27 import java.io.Reader ; 28 import java.util.Enumeration ; 29 import java.util.HashSet ; 30 31 import javax.swing.text.BadLocationException ; 32 import javax.swing.text.MutableAttributeSet ; 33 import javax.swing.text.html.HTML ; 34 import javax.swing.text.html.HTMLEditorKit ; 35 import javax.swing.text.html.parser.DocumentParser ; 36 37 import org.enhydra.xml.io.ErrorReporter; 38 import org.enhydra.xml.xmlc.XMLCException; 39 import org.enhydra.xml.xmlc.codegen.JavaLang; 40 import org.enhydra.xml.xmlc.dom.XMLCDocument; 41 import org.enhydra.xml.xmlc.html.parsers.HTMLDocBuilder; 42 import org.enhydra.xml.xmlc.misc.LineNumberMap; 43 import org.enhydra.xml.xmlc.parsers.ParseTracer; 44 import org.w3c.dom.Document ; 45 import org.w3c.dom.Node ; 46 import org.w3c.dom.html.HTMLBodyElement; 47 import org.w3c.dom.html.HTMLHtmlElement; 48 import org.w3c.dom.html.HTMLScriptElement; 49 50 61 class SwingParser extends HTMLEditorKit.ParserCallback { 62 66 private LineNumberMap fLineNumberMap; 67 68 72 private boolean fGotError = false; 73 74 77 private XMLCDocument fXmlcDoc; 78 79 82 private HTMLDocBuilder fDocBuilder; 83 84 89 class ParserError extends Error { 90 93 private Exception fCause; 94 95 98 public ParserError(Exception cause) { 99 super(cause.getMessage()); 100 fCause = cause; 101 fGotError = true; 102 } 103 104 107 public Throwable getCause() { 108 return fCause; 109 } 110 } 111 112 115 private static final String [] fSwingIgnoredPrefixes = { 116 "invalid.tagatt", "javascript.unsupported", "req.att", 119 "tag.unrecognized", 120 "end.unrecognized", 121 "unmatched.endtag", 122 "multi.tagatt", 123 "tag.ignoreimg" 124 }; 125 126 129 private static final String fIgnoreBodyPrefix = "tag.ignorebody"; 130 131 135 private static final HashSet fUnrecognizedAssumeEndTag = new HashSet (); 136 137 140 private ErrorReporter fReporter; 141 142 145 private ParseTracer fTracer; 146 147 150 private boolean fTracingEnabled; 151 152 155 static { 156 fUnrecognizedAssumeEndTag.add("noscript"); 157 fUnrecognizedAssumeEndTag.add("frameset"); 158 fUnrecognizedAssumeEndTag.add("noframes"); 159 fUnrecognizedAssumeEndTag.add("span"); 160 } 161 162 165 void parse(HTMLDocBuilder docBuilder, 166 ErrorReporter errorReporter, 167 ParseTracer tracer, 168 Reader input, 169 LineNumberMap lineNumberMap) throws XMLCException, IOException { 170 fDocBuilder = docBuilder; 171 fXmlcDoc = docBuilder.getXMLCDocument(); 172 fLineNumberMap = lineNumberMap; 173 fGotError = false; 174 fReporter = errorReporter; 175 fTracer = tracer; 176 fTracingEnabled = ((fTracer != null) && fTracer.enabled()); 177 178 try { 179 DocumentParser parser = new ParserAdaptor().getParser(); 180 parser.parse(input, this, true); 181 } catch (ParserError err) { 182 Throwable cause = err.getCause(); 183 if (cause instanceof XMLCException) { 184 throw (XMLCException)cause; 185 } else { 186 throw new XMLCException(cause); 187 } 188 } 189 Document document = fXmlcDoc.getDocument(); 190 if (fXmlcDoc.isHtmlFrameSet()) { 191 cleanupFrameSet(document); 192 } 193 checkNodes(document); 194 } 195 196 199 private void reportError(String msg, int pos) { 200 LineNumberMap.Line rec = fLineNumberMap.getLineFromOffset(pos); 201 fReporter.error(msg, rec.getFileName(), rec.getLineNum()); 202 } 203 204 208 private boolean isEndTag(MutableAttributeSet attrSet) { 209 return attrSet.isDefined(HTML.Attribute.ENDTAG); 210 } 211 212 216 private boolean assumeEndTag(HTML.Tag tag) { 217 return fUnrecognizedAssumeEndTag.contains(tag.toString()); 218 } 219 220 223 private void traceTag(String message, 224 HTML.Tag tag, 225 MutableAttributeSet attrSet) { 226 StringBuffer msg = new StringBuffer (message); 227 msg.append(": "); 228 msg.append(tag.toString()); 229 230 if (attrSet != null) { 231 msg.append(":"); 232 Enumeration keyes = attrSet.getAttributeNames(); 233 while (keyes.hasMoreElements()) { 234 Object attrKey = keyes.nextElement(); 235 Object attrValue = attrSet.getAttribute(attrKey); 236 msg.append(" " + attrKey + "=\"" + attrValue + "\""); 237 } 238 } 239 fTracer.trace(msg.toString()); 240 } 241 242 245 private void traceStartTag(String message, 246 HTML.Tag tag, 247 MutableAttributeSet attrSet) { 248 traceTag(message, tag, attrSet); 249 fTracer.enter(); 250 } 251 252 255 private void traceEndTag(String message, 256 HTML.Tag tag) { 257 StringBuffer msg = new StringBuffer (message); 258 msg.append(": "); 259 msg.append(tag.toString()); 260 fTracer.leave(); 261 fTracer.trace(msg.toString()); 262 } 263 264 268 private boolean ignore(String errorMsg) { 269 if (fXmlcDoc.isHtmlFrameSet() 271 && errorMsg.startsWith(fIgnoreBodyPrefix)) { 272 return true; 273 } 274 for (int i = 0; i < fSwingIgnoredPrefixes.length; i++) { 275 if (errorMsg.startsWith(fSwingIgnoredPrefixes[i])) { 276 return true; 277 } 278 } 279 return false; 280 } 281 282 285 private String tagMisMatchMsg(HTML.Tag tag) { 286 return "Close tag mismatch, got </" 287 + tag.toString().toUpperCase() + ">, expected </" 288 + fDocBuilder.getCurrentNode().getNodeName() + ">"; 289 } 290 291 296 private void processEndTagMisMatch(HTML.Tag tag, int pos) { 297 if (tag.toString().equalsIgnoreCase("form") 298 || tag.toString().equalsIgnoreCase("span")) { 299 if (fTracingEnabled) { 301 fTracer.trace("IGNORED: " + tagMisMatchMsg(tag) 302 + ", not modifying node stack"); 303 } 304 return; 305 } 306 Node currentNode = fDocBuilder.getCurrentNode(); 307 if (currentNode.getNodeName().equalsIgnoreCase("form") 308 || currentNode.getNodeName().equalsIgnoreCase("span")) { 309 if (fTracingEnabled) { 311 fTracer.trace("IGNORED: " + tagMisMatchMsg(tag) 312 + ", appears to be left on stack from previous error; removing"); 313 } 314 fDocBuilder.popCurrentNode(); 315 316 handleEndTag(tag, pos); 318 return; 319 } 320 321 handleError(tagMisMatchMsg(tag), pos); 323 } 324 325 328 private void processBeginTag(HTML.Tag tag, 329 MutableAttributeSet attrSet) { 330 String tagName = tag.toString(); 331 332 fDocBuilder.startElement(tagName); 333 if ((attrSet != null) && (attrSet.getAttributeCount() > 0)) { 334 Enumeration keyes = attrSet.getAttributeNames(); 335 while (keyes.hasMoreElements()) { 336 Object attrKey = keyes.nextElement(); 337 Object attrValue = attrSet.getAttribute(attrKey); 338 if (attrValue != null) { 339 String name = attrKey.toString(); 340 if (!name.equals(ParserAdaptor.IMPLIED_PSEUDO_ATTR)) { 341 fDocBuilder.addAttribute(name, attrValue.toString()); 342 } 343 } 344 } 345 } 346 } 347 348 351 private void processEndTag(HTML.Tag tag, 352 int pos) { 353 Node currentNode = fDocBuilder.getCurrentNode(); 354 if ((currentNode != null) 355 && !currentNode.getNodeName().equalsIgnoreCase(tag.toString())) { 356 processEndTagMisMatch(tag, pos); 357 } else { 358 fDocBuilder.finishElement(); 359 } 360 } 361 362 366 public void flush() throws BadLocationException { 367 } 368 369 373 public void handleText(char[] data, int pos) { 374 if (fGotError) { 375 return; 376 } 377 if (fTracingEnabled) { 378 fTracer.trace("TEXT: " + JavaLang.createStringConst(new String (data))); 379 } 380 fDocBuilder.addTextNode(new String (data)); 381 } 382 383 387 public void handleComment(char[] data, int pos) { 388 if (fGotError) { 389 return; 390 } 391 if (fTracingEnabled) { 392 fTracer.trace("COMMENT: " + JavaLang.createStringConst(new String (data))); 393 } 394 fDocBuilder.addComment(new String (data)); 395 } 396 397 401 public void handleStartTag(HTML.Tag tag, MutableAttributeSet attrSet, int pos) { 402 if (fGotError) { 403 return; 404 } 405 if (fTracingEnabled) { 406 traceStartTag("BEGIN TAG", tag, attrSet); 407 } 408 processBeginTag(tag, attrSet); 409 } 410 411 415 public void handleEndTag(HTML.Tag tag, int pos) { 416 if (fGotError) { 417 return; 418 } 419 if (fTracingEnabled) { 420 traceEndTag("END TAG", tag); 421 } 422 processEndTag(tag, pos); 423 } 424 425 429 public void handleSimpleTag(HTML.Tag tag, 430 MutableAttributeSet attrSet, 431 int pos) { 432 String tagName = tag.toString(); 433 434 if (fGotError || tagName.equals(ParserAdaptor.MAGIC_END_TAG)) { 436 return; 437 } 438 if (fTracingEnabled) { 439 traceTag("SIMPLE TAG", tag, attrSet); 440 } 441 442 448 if (isEndTag(attrSet)) { 449 if ((tag instanceof HTML.UnknownTag ) || tagName.equals("span")) { 450 try { 452 fDocBuilder.fixUnrecognizedTagNesting(tagName); 453 } catch (XMLCException except) { 454 reportError(except.toString(), pos); 455 } 456 } 457 } else { 458 processBeginTag(tag, attrSet); 459 processEndTag(tag, pos); 460 } 461 } 462 463 468 public void handleError(String errorMsg, 469 int pos) { 470 if (fGotError) { 471 return; 472 } 473 boolean ignored = ignore(errorMsg); 474 if (fTracingEnabled) { 475 if (ignored) { 476 fTracer.trace("IGNORE: " + errorMsg + ": " + pos); 477 } else { 478 fTracer.trace("ERROR: " + errorMsg + ": " + pos); 479 } 480 } 481 if (!ignored) { 482 reportError(errorMsg, pos); 483 } 484 } 485 486 491 private void checkScriptElement(HTMLScriptElement scriptElement) { 492 if (scriptElement.getFirstChild() == null) { 493 fReporter.error("Empty <SCRIPT> element found. The swing HTML parser discards javascript\n" 494 + " that is not in a comment"); 495 } 496 } 497 498 503 private void checkNodes(Node node) { 504 if (node instanceof HTMLScriptElement) { 505 checkScriptElement((HTMLScriptElement)node); 506 } 507 for (Node child = node.getFirstChild(); child != null; 508 child = child.getNextSibling()) { 509 checkNodes(child); 510 } 511 } 512 513 516 private void cleanupFrameSet(Document doc) { 517 Node htmlElem = null; 519 for (Node child = doc.getFirstChild(); child != null; 520 child = child.getNextSibling()) { 521 if (child instanceof HTMLHtmlElement) { 522 htmlElem = child; 523 break; 524 } 525 } 526 if (htmlElem == null) { 527 return; 528 } 529 530 Node bodyElem = null; 532 for (Node child = htmlElem.getFirstChild(); child != null; 533 child = child.getNextSibling()) { 534 if (child instanceof HTMLBodyElement) { 535 bodyElem = child; 536 break; 537 } 538 } 539 if (bodyElem == null) { 540 return; 541 } 542 543 for (Node child = bodyElem.getFirstChild(); child != null;) { 545 Node move = child; 546 child = child.getNextSibling(); 547 548 bodyElem.removeChild(move); 549 htmlElem.insertBefore(move, bodyElem); 550 } 551 552 htmlElem.removeChild(bodyElem); 554 } 555 } 556 | Popular Tags |