001 /* 002 * Copyright (c) 2007 Henri Sivonen 003 * 004 * Permission is hereby granted, free of charge, to any person obtaining a 005 * copy of this software and associated documentation files (the "Software"), 006 * to deal in the Software without restriction, including without limitation 007 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 008 * and/or sell copies of the Software, and to permit persons to whom the 009 * Software is furnished to do so, subject to the following conditions: 010 * 011 * The above copyright notice and this permission notice shall be included in 012 * all copies or substantial portions of the Software. 013 * 014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 017 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 020 * DEALINGS IN THE SOFTWARE. 021 */ 022 023 package nu.validator.htmlparser.sax; 024 025 import org.xml.sax.Attributes; 026 import org.xml.sax.ContentHandler; 027 import org.xml.sax.SAXException; 028 import org.xml.sax.ext.LexicalHandler; 029 030 import nu.validator.htmlparser.common.XmlViolationPolicy; 031 import nu.validator.htmlparser.impl.AttributesImpl; 032 import nu.validator.htmlparser.impl.TreeBuilder; 033 034 class SAXStreamer extends TreeBuilder<Attributes>{ 035 036 private ContentHandler contentHandler; 037 private LexicalHandler lexicalHandler; 038 private int depth; 039 040 SAXStreamer() { 041 super(XmlViolationPolicy.FATAL, false); 042 } 043 044 @Override 045 protected void addAttributesToElement(Attributes element, Attributes attributes) throws SAXException { 046 Attributes existingAttrs = element; 047 for (int i = 0; i < attributes.getLength(); i++) { 048 String qName = attributes.getQName(i); 049 if (existingAttrs.getIndex(qName) < 0) { 050 fatal(); 051 } 052 } 053 } 054 055 @Override 056 protected void appendCharacters(Attributes parent, char[] buf, int start, int length) throws SAXException { 057 contentHandler.characters(buf, start, length); 058 } 059 060 @Override 061 protected void appendChildrenToNewParent(Attributes oldParent, Attributes newParent) throws SAXException { 062 fatal(); 063 } 064 065 @Override 066 protected void appendComment(Attributes parent, char[] buf, int start, int length) throws SAXException { 067 if (lexicalHandler != null) { 068 lexicalHandler.comment(buf, start, length); 069 } 070 } 071 072 @Override 073 protected void appendCommentToDocument(char[] buf, int start, int length) 074 throws SAXException { 075 if (lexicalHandler != null) { 076 if (depth == 0) { 077 lexicalHandler.comment(buf, start, length); 078 } else { 079 fatal(); 080 } 081 } 082 } 083 084 @Override 085 protected Attributes createElement(String name, Attributes attributes) throws SAXException { 086 return attributes; 087 } 088 089 @Override 090 protected Attributes createHtmlElementSetAsRoot(Attributes attributes) throws SAXException { 091 return attributes; 092 } 093 094 @Override 095 protected void detachFromParent(Attributes element) throws SAXException { 096 fatal(); 097 } 098 099 @Override 100 protected void detachFromParentAndAppendToNewParent(Attributes child, Attributes newParent) throws SAXException { 101 } 102 103 @Override 104 protected boolean hasChildren(Attributes element) throws SAXException { 105 return false; 106 } 107 108 @Override 109 protected void insertBefore(Attributes child, Attributes sibling, Attributes parent) throws SAXException { 110 fatal(); 111 } 112 113 @Override 114 protected void insertCharactersBefore(char[] buf, int start, int length, Attributes sibling, Attributes parent) throws SAXException { 115 fatal(); 116 } 117 118 @Override 119 protected Attributes parentElementFor(Attributes child) throws SAXException { 120 fatal(); 121 throw new RuntimeException("Unreachable"); 122 } 123 124 @Override 125 protected Attributes shallowClone(Attributes element) throws SAXException { 126 return element; 127 } 128 129 public void setContentHandler(ContentHandler handler) { 130 contentHandler = handler; 131 } 132 133 public void setLexicalHandler(LexicalHandler handler) { 134 lexicalHandler = handler; 135 } 136 137 /** 138 * @see nu.validator.htmlparser.impl.TreeBuilder#appendDoctypeToDocument(java.lang.String, java.lang.String, java.lang.String) 139 */ 140 @Override 141 protected void appendDoctypeToDocument(String name, String publicIdentifier, String systemIdentifier) throws SAXException { 142 if (lexicalHandler != null) { 143 lexicalHandler.startDTD(name, publicIdentifier, systemIdentifier); 144 lexicalHandler.endDTD(); 145 } 146 } 147 148 /** 149 * @see nu.validator.htmlparser.impl.TreeBuilder#bodyClosed(java.lang.Object) 150 */ 151 @Override 152 protected void bodyClosed(Attributes body) throws SAXException { 153 contentHandler.endElement("http://www.w3.org/1999/xhtml", "body", "body"); 154 depth--; 155 } 156 157 /** 158 * @see nu.validator.htmlparser.impl.TreeBuilder#elementPopped(java.lang.String, java.lang.Object) 159 */ 160 @Override 161 protected void elementPopped(String name, Attributes node) throws SAXException { 162 contentHandler.endElement("http://www.w3.org/1999/xhtml", name, name); 163 depth--; 164 } 165 166 /** 167 * @see nu.validator.htmlparser.impl.TreeBuilder#elementPushed(java.lang.String, java.lang.Object) 168 */ 169 @Override 170 protected void elementPushed(String name, Attributes node) throws SAXException { 171 if (depth == 0) { 172 contentHandler.startPrefixMapping("", "http://www.w3.org/1999/xhtml"); 173 } 174 contentHandler.startElement("http://www.w3.org/1999/xhtml", name, name, node); 175 depth++; 176 } 177 178 /** 179 * @see nu.validator.htmlparser.impl.TreeBuilder#end() 180 */ 181 @Override 182 protected void end() throws SAXException { 183 contentHandler.endDocument(); 184 } 185 186 /** 187 * @see nu.validator.htmlparser.impl.TreeBuilder#htmlClosed(java.lang.Object) 188 */ 189 @Override 190 protected void htmlClosed(Attributes html) throws SAXException { 191 contentHandler.endElement("http://www.w3.org/1999/xhtml", "html", "html"); 192 contentHandler.endPrefixMapping(""); 193 depth--; 194 } 195 196 /** 197 * @see nu.validator.htmlparser.impl.TreeBuilder#start() 198 */ 199 @Override 200 protected void start(boolean fragment) throws SAXException { 201 contentHandler.setDocumentLocator(tokenizer); 202 if (fragment) { 203 depth = 1; 204 } else { 205 depth = 0; 206 contentHandler.startDocument(); 207 } 208 } 209 210 }