1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.doxia.util;
20
21 import javax.xml.parsers.ParserConfigurationException;
22 import javax.xml.parsers.SAXParser;
23 import javax.xml.parsers.SAXParserFactory;
24
25 import java.io.IOException;
26 import java.io.StringReader;
27 import java.util.Locale;
28 import java.util.regex.Matcher;
29 import java.util.regex.Pattern;
30
31 import org.apache.maven.doxia.markup.XmlMarkup;
32 import org.apache.maven.doxia.parser.ParseException;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.xml.sax.EntityResolver;
36 import org.xml.sax.InputSource;
37 import org.xml.sax.SAXException;
38 import org.xml.sax.SAXParseException;
39 import org.xml.sax.XMLReader;
40 import org.xml.sax.helpers.DefaultHandler;
41
42
43
44
45
46
47 public class XmlValidator {
48 private static final Logger LOGGER = LoggerFactory.getLogger(XmlValidator.class);
49
50
51 private XMLReader xmlReader;
52
53 private boolean validate = true;
54 private DefaultHandler defaultHandler;
55 private EntityResolver entityResolver;
56
57 public boolean isValidate() {
58 return validate;
59 }
60
61 public void setValidate(boolean validate) {
62 this.validate = validate;
63 }
64
65 public DefaultHandler getDefaultHandler() {
66 return defaultHandler;
67 }
68
69 public void setDefaultHandler(DefaultHandler defaultHandler) {
70 this.defaultHandler = defaultHandler;
71 }
72
73 public EntityResolver getEntityResolver() {
74 return entityResolver;
75 }
76
77 public void setEntityResolver(EntityResolver entityResolver) {
78 this.entityResolver = entityResolver;
79 }
80
81
82
83
84
85
86
87 public void validate(String content) throws ParseException {
88 try {
89 getXmlReader().parse(new InputSource(new StringReader(content)));
90 } catch (IOException | SAXException | ParserConfigurationException e) {
91 throw new ParseException("Error validating the model", e);
92 }
93 }
94
95
96
97
98
99
100 public XMLReader getXmlReader() throws SAXException, ParserConfigurationException {
101 if (xmlReader == null) {
102 SAXParserFactory parserFactory = SAXParserFactory.newInstance();
103 parserFactory.setNamespaceAware(true);
104 SAXParser parser = parserFactory.newSAXParser();
105
106 parser.setProperty(
107 "http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema");
108
109 parser.setProperty("http://apache.org/xml/properties/locale", Locale.ROOT);
110 xmlReader = parser.getXMLReader();
111 xmlReader.setFeature("http://xml.org/sax/features/validation", isValidate());
112 xmlReader.setFeature("http://apache.org/xml/features/validation/dynamic", isValidate());
113 xmlReader.setFeature("http://apache.org/xml/features/validation/schema", isValidate());
114 xmlReader.setErrorHandler(getDefaultHandler());
115 xmlReader.setEntityResolver(getEntityResolver());
116 }
117
118 return xmlReader;
119 }
120
121
122
123
124 public static class MessagesErrorHandler extends DefaultHandler {
125 private static final int TYPE_UNKNOWN = 0;
126
127 private static final int TYPE_WARNING = 1;
128
129 private static final int TYPE_ERROR = 2;
130
131 private static final int TYPE_FATAL = 3;
132
133 private static final String EOL = XmlMarkup.EOL;
134
135
136 private static final Pattern ELEMENT_TYPE_PATTERN =
137 Pattern.compile("Element type \".*\" must be declared.", Pattern.DOTALL);
138
139
140 @Override
141 public void warning(SAXParseException e) throws SAXException {
142 processException(TYPE_WARNING, e);
143 }
144
145
146 @Override
147 public void error(SAXParseException e) throws SAXException {
148 Matcher m = ELEMENT_TYPE_PATTERN.matcher(e.getMessage());
149 if (!m.find()) {
150 processException(TYPE_ERROR, e);
151 }
152 }
153
154
155 @Override
156 public void fatalError(SAXParseException e) throws SAXException {
157 processException(TYPE_FATAL, e);
158 }
159
160 private void processException(int type, SAXParseException e) throws SAXException {
161 StringBuilder message = new StringBuilder();
162
163 switch (type) {
164 case TYPE_WARNING:
165 message.append("Warning:");
166 break;
167
168 case TYPE_ERROR:
169 message.append("Error:");
170 break;
171
172 case TYPE_FATAL:
173 message.append("Fatal error:");
174 break;
175
176 case TYPE_UNKNOWN:
177 default:
178 message.append("Unknown:");
179 break;
180 }
181
182 message.append(EOL);
183 message.append(" Public ID: ").append(e.getPublicId()).append(EOL);
184 message.append(" System ID: ").append(e.getSystemId()).append(EOL);
185 message.append(" Line number: ").append(e.getLineNumber()).append(EOL);
186 message.append(" Column number: ").append(e.getColumnNumber()).append(EOL);
187 message.append(" Message: ").append(e.getMessage()).append(EOL);
188
189 final String logMessage = message.toString();
190
191 switch (type) {
192 case TYPE_WARNING:
193 LOGGER.warn(logMessage);
194 break;
195
196 case TYPE_UNKNOWN:
197 case TYPE_ERROR:
198 case TYPE_FATAL:
199 default:
200 throw new SAXException(logMessage);
201 }
202 }
203 }
204 }