1 11 package org.eclipse.pde.internal.core.builders; 12 13 import java.util.Stack ; 14 import java.util.StringTokenizer ; 15 16 import org.eclipse.core.resources.IFile; 17 import org.eclipse.core.runtime.IProgressMonitor; 18 import org.eclipse.osgi.util.NLS; 19 import org.eclipse.pde.internal.core.PDECoreMessages; 20 import org.w3c.dom.Attr ; 21 import org.w3c.dom.Element ; 22 import org.w3c.dom.Node ; 23 import org.w3c.dom.NodeList ; 24 import org.w3c.dom.Text ; 25 26 27 public class SchemaErrorReporter extends XMLErrorReporter { 28 29 class StackEntry { 30 String tag; 31 int line; 32 33 public StackEntry(String tag, int line) { 34 this.tag = tag; 35 this.line = line; 36 } 37 } 38 39 public static final String [] forbiddenEndTagKeys = 40 { 41 "area", "base", "basefont", "br", "col", "frame", "hr", "img", "input", "isindex", "link", "meta", "param" }; 55 public static final String [] optionalEndTagKeys = 56 { 57 "body", "colgroup", "dd", "dt", "head", "html", "li", "option", "p", "tbody", "td", "tfoot", "th", "thead", "tr" }; 73 74 public SchemaErrorReporter(IFile file) { 75 super(file); 76 } 77 78 public void validateContent(IProgressMonitor monitor) { 79 Element element = getDocumentRoot(); 80 if (element != null) 81 validateElement(element); 82 } 83 84 private void validateElement(Element element) { 85 if (element.getNodeName().equals("attribute")) validateAttribute(element); 87 88 NodeList children = element.getChildNodes(); 89 for (int i = 0; i < children.getLength(); i++) { 90 Node child = children.item(i); 91 if (child instanceof Element ) { 92 if (child.getNodeName().equals("annotation")) { validateAnnotation((Element )child); 94 } else { 95 validateElement((Element )child); 96 } 97 } 98 } 99 } 100 101 private void validateAnnotation(Element element) { 102 NodeList children = element.getChildNodes(); 103 for (int i = 0; i < children.getLength(); i++) { 104 Node child = children.item(i); 105 if (child instanceof Element && child.getNodeName().equals("documentation")) { validateDocumentation((Element )child); 107 } 108 } 109 } 110 111 private void validateDocumentation(Element element) { 112 int flag = CompilerFlags.getFlag(fProject, CompilerFlags.S_OPEN_TAGS); 113 114 NodeList children = element.getChildNodes(); 115 for (int i = 0; i < children.getLength(); i++) { 116 if (children.item(i) instanceof Text ) { 117 Text textNode = (Text )children.item(i); 118 StringTokenizer text = new StringTokenizer (textNode.getData(), "<>", true); 120 int lineNumber = getLine(element); 121 Stack stack = new Stack (); 122 boolean errorReported = false; 123 while (text.hasMoreTokens()) { 124 if (errorReported) 125 break; 126 127 String next = text.nextToken(); 128 if (next.equals("<")) { if (text.countTokens() > 2) { 130 String tagName = text.nextToken(); 131 String closing = text.nextToken(); 132 if (closing.equals(">")) { if (tagName.startsWith("!--") || tagName.endsWith("--") || tagName.startsWith("?") || tagName.endsWith("?")) { lineNumber += getLineBreakCount(tagName); 139 continue; 140 } 141 142 if (tagName.endsWith("/")) { tagName = getTagName(tagName.substring(0, tagName.length() - 1)); 144 if (forbiddenEndTag(tagName)) { 145 report(NLS.bind(PDECoreMessages.Builders_Schema_forbiddenEndTag, tagName), lineNumber, flag, PDEMarkerFactory.CAT_OTHER); 146 errorReported = true; 147 } 148 } else if (tagName.startsWith("/")) { lineNumber += getLineBreakCount(tagName); 150 tagName = tagName.substring(1).trim(); 151 boolean found = false; 152 while (!stack.isEmpty()) { 153 StackEntry entry = (StackEntry)stack.peek(); 154 if (entry.tag.equalsIgnoreCase(tagName)) { 155 stack.pop(); 156 found = true; 157 break; 158 } else if (optionalEndTag(entry.tag)) { 159 stack.pop(); 160 } else { 161 break; 162 } 163 } 164 if (stack.isEmpty() && !found) { 165 report(NLS.bind(PDECoreMessages.Builders_Schema_noMatchingStartTag, tagName), lineNumber, flag, PDEMarkerFactory.CAT_OTHER); 166 errorReported = true; 167 } 168 } else { 169 String shortTag = getTagName(tagName); 170 if (!forbiddenEndTag(shortTag)) 171 stack.push(new StackEntry(shortTag, lineNumber)); 172 lineNumber += getLineBreakCount(tagName); 173 } 174 } 175 } 176 } else { 177 lineNumber += getLineBreakCount(next); 178 } 179 } 180 if (!errorReported) { 181 if (!stack.isEmpty()) { 182 StackEntry entry = (StackEntry)stack.pop(); 183 if (!optionalEndTag(entry.tag)) 184 report(NLS.bind(PDECoreMessages.Builders_Schema_noMatchingEndTag, entry.tag), entry.line, flag, PDEMarkerFactory.CAT_OTHER); 185 } 186 stack.clear(); 187 } 188 } 189 } 190 } 191 192 private String getTagName(String text) { 193 StringTokenizer tokenizer = new StringTokenizer (text); 194 return tokenizer.nextToken(); 195 } 196 197 private boolean optionalEndTag(String tag) { 198 for (int i = 0; i < optionalEndTagKeys.length; i++) { 199 if (tag.equalsIgnoreCase(optionalEndTagKeys[i])) 200 return true; 201 } 202 return false; 203 } 204 205 private boolean forbiddenEndTag(String tag) { 206 for (int i = 0; i < forbiddenEndTagKeys.length; i++) { 207 if (tag.equalsIgnoreCase(forbiddenEndTagKeys[i])) 208 return true; 209 } 210 return false; 211 } 212 213 private int getLineBreakCount(String tag){ 214 StringTokenizer tokenizer = new StringTokenizer (tag, "\n", true); int token = 0; 216 while (tokenizer.hasMoreTokens()){ 217 if (tokenizer.nextToken().equals("\n")) token++; 219 } 220 return token; 221 } 222 223 private void validateAttribute(Element element) { 224 validateUse(element); 225 } 226 227 private void validateUse(Element element) { 228 Attr use = element.getAttributeNode("use"); Attr value = element.getAttributeNode("value"); if (use != null && "default".equals(use.getValue()) && value == null) { report(NLS.bind(PDECoreMessages.Builders_Schema_valueRequired, element.getNodeName()), 232 getLine(element), 233 CompilerFlags.ERROR, 234 PDEMarkerFactory.CAT_OTHER); 235 } else if (use == null && value != null) { 236 report(NLS.bind(PDECoreMessages.Builders_Schema_valueNotRequired, element.getNodeName()), 237 getLine(element), 238 CompilerFlags.ERROR, 239 PDEMarkerFactory.CAT_OTHER); 240 } 241 } 242 243 } 244 | Popular Tags |