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