File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\util\TableNestChecker.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24 package hudson.util;
25
26 import org.xml.sax.helpers.XMLFilterImpl;
27 import org.xml.sax.XMLFilter;
28 import org.xml.sax.ContentHandler;
29 import org.xml.sax.Attributes;
30 import org.xml.sax.SAXException;
31 import org.apache.commons.jelly.XMLOutput;
32
33 import java.util.Locale;
34 import java.util.Stack;
35 import java.util.Map;
36 import java.util.HashMap;
37 import java.util.Set;
38 import java.util.HashSet;
39 import java.util.Arrays;
40
41 /**
42 * {@link XMLFilter} that checks the proper nesting of table related tags.
43 *
44 * <p>
45 * Browser often "fixes" HTML by moving tables into the right place,
46 * so failure to generate proper tables can result in a hard-to-track bugs.
47 *
48 * <p>
49 * TODO: where to apply this in stapler?
50 * JellyClassTearOff creates XMLOutput. Perhaps we define a decorator?
51 * We can also wrap Script. would that work better?
52 *
53 * @author Kohsuke Kawaguchi
54 */
55 public class TableNestChecker extends XMLFilterImpl {
56
57 private final Stack<Checker> elements = new Stack<Checker>();
58 private final Stack<String> tagNames = new Stack<String>();
59
60 public static void applyTo(XMLOutput xo) {
61 xo.setContentHandler(new TableNestChecker(xo.getContentHandler()));
62 }
63
64 public TableNestChecker() {
65 elements.push(ALL_ALLOWED);
66 }
67
68 public TableNestChecker(ContentHandler target) {
69 this();
70 setContentHandler(target);
71 }
72
73 @Override
74 public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
75 String tagName = localName.toUpperCase(Locale.ENGLISH);
76
77 // make sure that this tag occurs in the proper context
78 if(!elements.peek().isAllowed(tagName))
79 throw new SAXException(tagName+" is not allowed inside "+tagNames.peek());
80
81 Checker next = CHECKERS.get(tagName);
82 if(next==null) next = ALL_ALLOWED;
83 elements.push(next);
84 tagNames.push(tagName);
85
86 super.startElement(uri, localName, qName, atts);
87 }
88
89 @Override
90 public void endElement(String uri, String localName, String qName) throws SAXException {
91 elements.pop();
92 tagNames.pop();
93 super.endElement(uri, localName, qName);
94 }
95
96
97 private interface Checker {
98 boolean isAllowed(String childTag);
99 }
100
101 private static final Checker ALL_ALLOWED = new Checker() {
102 public boolean isAllowed(String childTag) {
103 return true;
104 }
105 };
106
107 private static final class InList implements Checker {
108 private final Set<String> tags;
109
110 private InList(String... tags) {
111 this.tags = new HashSet<String>(Arrays.asList(tags));
112 }
113
114 public boolean isAllowed(String childTag) {
115 return tags.contains(childTag);
116 }
117 }
118
119 private static final Map<String,Checker> CHECKERS = new HashMap<String, Checker>();
120
121 static {
122 CHECKERS.put("TABLE",new InList("TR","THEAD","TBODY"));
123 InList rows = new InList("TR");
124 CHECKERS.put("THEAD",rows);
125 CHECKERS.put("THEAD",rows);
126 CHECKERS.put("TR", new InList("TD","TH"));
127 }
128 }
129