1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.helger.schematron.xslt;
18
19 import java.net.URL;
20 import java.util.Locale;
21 import java.util.Map;
22
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import javax.annotation.concurrent.NotThreadSafe;
26 import javax.xml.transform.ErrorListener;
27 import javax.xml.transform.Transformer;
28 import javax.xml.transform.TransformerException;
29 import javax.xml.transform.URIResolver;
30 import javax.xml.transform.dom.DOMResult;
31 import javax.xml.transform.dom.DOMSource;
32
33 import org.oclc.purl.dsdl.svrl.SchematronOutputType;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Node;
38 import org.xml.sax.EntityResolver;
39
40 import com.helger.commons.ValueEnforcer;
41 import com.helger.commons.annotation.ReturnsMutableCopy;
42 import com.helger.commons.annotation.ReturnsMutableObject;
43 import com.helger.commons.collection.impl.CommonsLinkedHashMap;
44 import com.helger.commons.collection.impl.ICommonsOrderedMap;
45 import com.helger.commons.io.resource.IReadableResource;
46 import com.helger.commons.state.EValidity;
47 import com.helger.commons.string.ToStringGenerator;
48 import com.helger.commons.traits.IGenericImplTrait;
49 import com.helger.schematron.AbstractSchematronResource;
50 import com.helger.schematron.SchematronDebug;
51 import com.helger.schematron.svrl.SVRLMarshaller;
52 import com.helger.schematron.xslt.validator.ISchematronXSLTValidator;
53 import com.helger.schematron.xslt.validator.SchematronXSLTValidatorDefault;
54 import com.helger.xml.XMLFactory;
55 import com.helger.xml.serialize.write.XMLWriter;
56 import com.helger.xml.transform.DefaultTransformURIResolver;
57 import com.helger.xml.transform.LoggingTransformErrorListener;
58
59 import net.sf.saxon.jaxp.TransformerImpl;
60 import net.sf.saxon.lib.StandardLogger;
61 import net.sf.saxon.s9api.XsltTransformer;
62 import net.sf.saxon.trace.TraceEventMulticaster;
63 import net.sf.saxon.trace.XSLTTraceListener;
64
65
66
67
68
69
70
71
72
73 @NotThreadSafe
74 public abstract class AbstractSchematronXSLTBasedResourceml#AbstractSchematronXSLTBasedResource">AbstractSchematronXSLTBasedResource <IMPLTYPE extends AbstractSchematronXSLTBasedResource <IMPLTYPE>>
75 extends
76 AbstractSchematronResource implements
77 ISchematronXSLTBasedResource,
78 IGenericImplTrait <IMPLTYPE>
79 {
80 private static final Logger LOGGER = LoggerFactory.getLogger (AbstractSchematronXSLTBasedResource.class);
81
82 protected ErrorListener m_aCustomErrorListener;
83 protected URIResolver m_aCustomURIResolver = new DefaultTransformURIResolver ();
84 protected final ICommonsOrderedMap <String, Object> m_aCustomParameters = new CommonsLinkedHashMap <> ();
85 private ISchematronXSLTValidator m_aXSLTValidator = new SchematronXSLTValidatorDefault ();
86
87 public AbstractSchematronXSLTBasedResource (@Nonnull final IReadableResource aSCHResource)
88 {
89 super (aSCHResource);
90
91
92 final URL aBaseURL = aSCHResource.getAsURL ();
93 setURIResolver (new DefaultTransformURIResolver ().setDefaultBase (aBaseURL != null ? aBaseURL.toExternalForm ()
94 : null));
95 }
96
97 @Nullable
98 public ErrorListener getErrorListener ()
99 {
100 return m_aCustomErrorListener;
101 }
102
103 @Nonnull
104 public final IMPLTYPE setErrorListener (@Nullable final ErrorListener aCustomErrorListener)
105 {
106 m_aCustomErrorListener = aCustomErrorListener;
107 return thisAsT ();
108 }
109
110 @Nullable
111 public URIResolver getURIResolver ()
112 {
113 return m_aCustomURIResolver;
114 }
115
116 @Nonnull
117 public final IMPLTYPE setURIResolver (@Nullable final URIResolver aCustomURIResolver)
118 {
119 m_aCustomURIResolver = aCustomURIResolver;
120 return thisAsT ();
121 }
122
123 @Nonnull
124 @ReturnsMutableObject
125 public final ICommonsOrderedMap <String, Object> parameters ()
126 {
127 return m_aCustomParameters;
128 }
129
130 @Deprecated
131 public boolean hasParameters ()
132 {
133 return m_aCustomParameters.isNotEmpty ();
134 }
135
136 @Nonnull
137 @ReturnsMutableCopy
138 @Deprecated
139 public ICommonsOrderedMap <String, Object> getParameters ()
140 {
141 return m_aCustomParameters.getClone ();
142 }
143
144 @Nonnull
145 @Deprecated
146 public IMPLTYPE setParameters (@Nullable final Map <String, ?> aCustomParameters)
147 {
148 m_aCustomParameters.setAll (aCustomParameters);
149 return thisAsT ();
150 }
151
152
153
154
155
156
157
158
159
160
161 @Nonnull
162 public final IMPLTYPE setEntityResolver (@Nullable final EntityResolver aEntityResolver)
163 {
164 internalSetEntityResolver (aEntityResolver);
165 return thisAsT ();
166 }
167
168
169
170
171
172 @Nullable
173 public abstract ISchematronXSLTBasedProvider getXSLTProvider ();
174
175
176
177
178 @Nonnull
179 public ISchematronXSLTValidator getXSLTValidator ()
180 {
181 return m_aXSLTValidator;
182 }
183
184 @Nonnull
185 public final IMPLTYPE setXSLTValidator (@Nonnull final ISchematronXSLTValidator aXSLTValidator)
186 {
187 ValueEnforcer.notNull (aXSLTValidator, "XSLTValidator");
188 m_aXSLTValidator = aXSLTValidator;
189 return thisAsT ();
190 }
191
192 public final boolean isValidSchematron ()
193 {
194 final ISchematronXSLTBasedProvider aXSLTProvider = getXSLTProvider ();
195 return aXSLTProvider != null && aXSLTProvider.isValidSchematron ();
196 }
197
198 @Nonnull
199 public EValidity getSchematronValidity (@Nonnull final Node aXMLNode,
200 @Nullable final String sBaseURI) throws Exception
201 {
202 ValueEnforcer.notNull (aXMLNode, "XMLNode");
203
204
205 final SchematronOutputType aSO = applySchematronValidationToSVRL (aXMLNode, sBaseURI);
206 if (aSO == null)
207 return EValidity.INVALID;
208
209
210 return m_aXSLTValidator.getSchematronValidity (aSO);
211 }
212
213 @Nullable
214 public final Document applySchematronValidation (@Nonnull final Node aXMLNode,
215 @Nullable final String sBaseURI) throws TransformerException
216 {
217 ValueEnforcer.notNull (aXMLNode, "XMLNode");
218
219 final ISchematronXSLTBasedProvider aXSLTProvider = getXSLTProvider ();
220 if (aXSLTProvider == null || !aXSLTProvider.isValidSchematron ())
221 {
222
223 return null;
224 }
225
226
227 if (SchematronDebug.isShowCreatedXSLT ())
228 LOGGER.info ("Created XSLT document: " + XMLWriter.getNodeAsString (aXSLTProvider.getXSLTDocument ()));
229
230
231 final Document ret = XMLFactory.newDocument ();
232
233
234
235 final Transformer aTransformer = aXSLTProvider.getXSLTTransformer ();
236
237
238
239 if (m_aCustomErrorListener != null)
240 aTransformer.setErrorListener (m_aCustomErrorListener);
241 else
242 aTransformer.setErrorListener (new LoggingTransformErrorListener (Locale.US));
243
244
245 if (m_aCustomURIResolver != null)
246 aTransformer.setURIResolver (m_aCustomURIResolver);
247
248
249 if (m_aCustomParameters != null)
250 for (final Map.Entry <String, ?> aEntry : m_aCustomParameters.entrySet ())
251 aTransformer.setParameter (aEntry.getKey (), aEntry.getValue ());
252
253 if (LOGGER.isDebugEnabled ())
254 LOGGER.debug ("Applying Schematron XSLT on XML [start]");
255
256
257 if (false)
258 if (aTransformer.getClass ().getName ().equals ("net.sf.saxon.jaxp.TransformerImpl"))
259 {
260 final XsltTransformer aXT = ((TransformerImpl) aTransformer).getUnderlyingXsltTransformer ();
261
262 aXT.setMessageListener ( (a, b, c) -> LOGGER.info ("MessageListener: " + a + ", " + b + ", " + c));
263 aXT.setTraceFunctionDestination (new StandardLogger (System.err));
264 if (false)
265 aXT.getUnderlyingController ().setTraceListener (new XSLTTraceListener ());
266 if (false)
267 {
268 final XSLTTraceListener aTL = new XSLTTraceListener ();
269 aTL.setOutputDestination (new StandardLogger (System.err));
270 aXT.getUnderlyingController ().setTraceListener (TraceEventMulticaster.add (aTL, null));
271 }
272
273 if (false)
274 System.out.println ("mode=" + aXT.getInitialMode ());
275 if (false)
276 System.out.println ("temp=" + aXT.getInitialTemplate ());
277 if (false)
278 System.out.println (aTransformer.getOutputProperties ());
279 }
280
281
282 {
283 final DOMSource aSource = new DOMSource (aXMLNode);
284 aSource.setSystemId (sBaseURI);
285 aTransformer.transform (aSource, new DOMResult (ret));
286 }
287
288 if (LOGGER.isDebugEnabled ())
289 LOGGER.debug ("Applying Schematron XSLT on XML [end]");
290
291
292 if (SchematronDebug.isShowCreatedSVRL ())
293 LOGGER.info ("Created SVRL:\n" + XMLWriter.getNodeAsString (ret));
294
295 return ret;
296 }
297
298 @Nullable
299 public SchematronOutputType applySchematronValidationToSVRL (@Nonnull final Node aXMLSource,
300 @Nullable final String sBaseURI) throws Exception
301 {
302 final Document aDoc = applySchematronValidation (aXMLSource, sBaseURI);
303 if (aDoc == null)
304 return null;
305
306
307 if (aDoc.getDocumentElement () == null)
308 throw new IllegalStateException ("Internal error: created SVRL DOM Document has no document node!");
309 return new SVRLMarshaller ().read (aDoc);
310 }
311
312 @Override
313 public String toString ()
314 {
315 return ToStringGenerator.getDerived (super.toString ()).append ("XSLTValidator", m_aXSLTValidator).getToString ();
316 }
317 }