View Javadoc
1   /**
2    * Copyright (C) 2014-2018 Philip Helger (www.helger.com)
3    * philip[at]helger[dot]com
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *         http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package com.helger.schematron.pure.exchange;
18  
19  import javax.annotation.Nonnull;
20  import javax.annotation.Nullable;
21  import javax.annotation.concurrent.Immutable;
22  
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.xml.sax.EntityResolver;
26  
27  import com.helger.commons.ValueEnforcer;
28  import com.helger.commons.io.resource.IReadableResource;
29  import com.helger.commons.string.StringParser;
30  import com.helger.commons.string.ToStringGenerator;
31  import com.helger.schematron.CSchematron;
32  import com.helger.schematron.CSchematronXML;
33  import com.helger.schematron.SchematronDebug;
34  import com.helger.schematron.SchematronHelper;
35  import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
36  import com.helger.schematron.pure.errorhandler.LoggingPSErrorHandler;
37  import com.helger.schematron.pure.model.*;
38  import com.helger.schematron.pure.model.PSDir.EDirValue;
39  import com.helger.schematron.pure.model.PSRichGroup.ESpace;
40  import com.helger.xml.microdom.IMicroDocument;
41  import com.helger.xml.microdom.IMicroElement;
42  import com.helger.xml.microdom.IMicroText;
43  import com.helger.xml.microdom.serialize.MicroWriter;
44  import com.helger.xml.serialize.read.SAXReaderSettings;
45  
46  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
47  
48  /**
49   * Utility class for reading all Schematron elements from a resource.
50   *
51   * @author Philip Helger
52   */
53  @Immutable
54  @SuppressFBWarnings ("JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS")
55  public class PSReader
56  {
57    private static final Logger LOGGER = LoggerFactory.getLogger (PSReader.class);
58  
59    private final IReadableResource m_aResource;
60    private final IPSErrorHandler m_aErrorHandler;
61    private final EntityResolver m_aEntityResolver;
62  
63    /**
64     * Constructor without an error handler
65     *
66     * @param aResource
67     *        The resource to read the Schematron from. May not be
68     *        <code>null</code>.
69     */
70    public PSReader (@Nonnull final IReadableResource aResource)
71    {
72      this (aResource, null, null);
73    }
74  
75    /**
76     * Constructor with an error handler
77     *
78     * @param aResource
79     *        The resource to read the Schematron from. May not be
80     *        <code>null</code>.
81     * @param aErrorHandler
82     *        The error handler to use. May be <code>null</code>. If the error
83     *        handler is <code>null</code> a {@link LoggingPSErrorHandler} is
84     *        automatically created and used.
85     */
86    public PSReader (@Nonnull final IReadableResource aResource, @Nullable final IPSErrorHandler aErrorHandler)
87    {
88      this (aResource, aErrorHandler, null);
89    }
90  
91    /**
92     * Constructor with an error handler
93     *
94     * @param aResource
95     *        The resource to read the Schematron from. May not be
96     *        <code>null</code>.
97     * @param aErrorHandler
98     *        The error handler to use. May be <code>null</code>. If the error
99     *        handler is <code>null</code> a {@link LoggingPSErrorHandler} is
100    *        automatically created and used.
101    * @param aEntityResolver
102    *        The XML entity resolver to be used. May be <code>null</code>.
103    * @since 4.1.1
104    */
105   public PSReader (@Nonnull final IReadableResource aResource,
106                    @Nullable final IPSErrorHandler aErrorHandler,
107                    @Nullable final EntityResolver aEntityResolver)
108   {
109     ValueEnforcer.notNull (aResource, "Resource");
110     m_aResource = aResource;
111     m_aErrorHandler = aErrorHandler != null ? aErrorHandler : new LoggingPSErrorHandler ();
112     m_aEntityResolver = aEntityResolver;
113   }
114 
115   /**
116    * @return The resource from which the Schematron schema is read. Never
117    *         <code>null</code>.
118    */
119   @Nonnull
120   public IReadableResource getResource ()
121   {
122     return m_aResource;
123   }
124 
125   /**
126    * @return The error handler used. If no error handler was passed in the
127    *         constructor, than a {@link LoggingPSErrorHandler} is automatically
128    *         used.
129    */
130   @Nonnull
131   public IPSErrorHandler getErrorHandler ()
132   {
133     return m_aErrorHandler;
134   }
135 
136   /**
137    * Utility method to get a real attribute value, by trimming spaces, if the
138    * value is non-<code>null</code>.
139    *
140    * @param sAttrValue
141    *        The source attribute value. May be <code>null</code>.
142    * @return <code>null</code> if the input parameter is <code>null</code>.
143    */
144   @Nullable
145   private static String _getAttributeValue (@Nullable final String sAttrValue)
146   {
147     return sAttrValue == null ? null : sAttrValue.trim ();
148   }
149 
150   /**
151    * Emit a warning with the registered error handler.
152    *
153    * @param aSourceElement
154    *        The source element where the error occurred.
155    * @param sMessage
156    *        The main warning message.
157    */
158   private void _warn (@Nonnull final IPSElement aSourceElement, @Nonnull final String sMessage)
159   {
160     ValueEnforcer.notNull (aSourceElement, "SourceElement");
161     ValueEnforcer.notNull (sMessage, "Message");
162 
163     m_aErrorHandler.warn (m_aResource, aSourceElement, sMessage);
164   }
165 
166   /**
167    * Read an &lt;active&gt; element
168    *
169    * @param eActive
170    *        The source micro element. Never <code>null</code>.
171    * @return The created domain object. May not be <code>null</code>.
172    */
173   @Nonnull
174   public PSActive readActiveFromXML (@Nonnull final IMicroElement eActive)
175   {
176     final PSActivere/model/PSActive.html#PSActive">PSActive ret = new PSActive ();
177     eActive.forAllAttributes ( (sNS, sAttrName, sVal) -> {
178       final String sAttrValue = _getAttributeValue (sVal);
179       if (sAttrName.equals (CSchematronXML.ATTR_PATTERN))
180         ret.setPattern (sAttrValue);
181       else
182         ret.addForeignAttribute (sAttrName, sAttrValue);
183     });
184 
185     eActive.forAllChildren (aActiveChild -> {
186       switch (aActiveChild.getType ())
187       {
188         case TEXT:
189           ret.addText (((IMicroText) aActiveChild).getNodeValue ());
190           break;
191         case ELEMENT:
192           final IMicroElement eElement = (IMicroElement) aActiveChild;
193           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
194           {
195             final String sLocalName = eElement.getLocalName ();
196             if (sLocalName.equals (CSchematronXML.ELEMENT_DIR))
197               ret.addDir (readDirFromXML (eElement));
198             else
199               if (sLocalName.equals (CSchematronXML.ELEMENT_EMPH))
200                 ret.addEmph (readEmphFromXML (eElement));
201               else
202                 if (sLocalName.equals (CSchematronXML.ELEMENT_SPAN))
203                   ret.addSpan (readSpanFromXML (eElement));
204                 else
205                   _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
206           }
207           else
208             ret.addForeignElement (eElement.getClone ());
209 
210           break;
211         case COMMENT:
212           // Ignore comments
213           break;
214         default:
215           _warn (ret, "Unsupported child node: " + aActiveChild);
216       }
217     });
218     return ret;
219   }
220 
221   private void _handleRichGroup (@Nonnull final String sAttrName,
222                                  @Nonnull final String sAttrValue,
223                                  @Nonnull final PSRichGroup aRichGroup)
224   {
225     if (sAttrName.equals (CSchematronXML.ATTR_ICON))
226       aRichGroup.setIcon (sAttrValue);
227     else
228       if (sAttrName.equals (CSchematronXML.ATTR_SEE))
229         aRichGroup.setSee (sAttrValue);
230       else
231         if (sAttrName.equals (CSchematronXML.ATTR_FPI))
232           aRichGroup.setFPI (sAttrValue);
233         else
234           if (sAttrName.equals (CSchematronXML.ATTR_XML_LANG))
235             aRichGroup.setXmlLang (sAttrValue);
236           else
237             if (sAttrName.equals (CSchematronXML.ATTR_XML_SPACE))
238               aRichGroup.setXmlSpace (ESpace.getFromIDOrNull (sAttrValue));
239   }
240 
241   private void _handleLinkableGroup (@Nonnull final String sAttrName,
242                                      @Nonnull final String sAttrValue,
243                                      @Nonnull final PSLinkableGroup aLinkableGroup)
244   {
245     if (sAttrName.equals (CSchematronXML.ATTR_ROLE))
246       aLinkableGroup.setRole (sAttrValue);
247     else
248       if (sAttrName.equals (CSchematronXML.ATTR_SUBJECT))
249         aLinkableGroup.setSubject (sAttrValue);
250   }
251 
252   /**
253    * Read an &lt;assert&gt; or a &lt;report&gt; element
254    *
255    * @param eAssertReport
256    *        The source micro element. Never <code>null</code>.
257    * @return The created domain object. May not be <code>null</code>.
258    */
259   @Nonnull
260   public PSAssertReport readAssertReportFromXML (@Nonnull final IMicroElement eAssertReport)
261   {
262     final PSAssertReportel/PSAssertReport.html#PSAssertReport">PSAssertReport ret = new PSAssertReport (eAssertReport.getLocalName ()
263                                                                 .equals (CSchematronXML.ELEMENT_ASSERT));
264 
265     final PSRichGroupSRichGroup.html#PSRichGroup">PSRichGroup aRichGroup = new PSRichGroup ();
266     final PSLinkableGroupeGroup.html#PSLinkableGroup">PSLinkableGroup aLinkableGroup = new PSLinkableGroup ();
267     eAssertReport.forAllAttributes ( (sNS, sAttrName, sVal) -> {
268       final String sAttrValue = _getAttributeValue (sVal);
269       if (sAttrName.equals (CSchematronXML.ATTR_TEST))
270         ret.setTest (sAttrValue);
271       else
272         if (sAttrName.equals (CSchematronXML.ATTR_FLAG))
273           ret.setFlag (sAttrValue);
274         else
275           if (sAttrName.equals (CSchematronXML.ATTR_ID))
276             ret.setID (sAttrValue);
277           else
278             if (sAttrName.equals (CSchematronXML.ATTR_DIAGNOSTICS))
279               ret.setDiagnostics (sAttrValue);
280             else
281               if (PSRichGroup.isRichAttribute (sAttrName))
282                 _handleRichGroup (sAttrName, sAttrValue, aRichGroup);
283               else
284                 if (PSLinkableGroup.isLinkableAttribute (sAttrName))
285                   _handleLinkableGroup (sAttrName, sAttrValue, aLinkableGroup);
286                 else
287                   ret.addForeignAttribute (sAttrName, sAttrValue);
288     });
289     ret.setRich (aRichGroup);
290     ret.setLinkable (aLinkableGroup);
291 
292     eAssertReport.forAllChildren (aAssertReportChild -> {
293       switch (aAssertReportChild.getType ())
294       {
295         case TEXT:
296           ret.addText (((IMicroText) aAssertReportChild).getNodeValue ());
297           break;
298         case ELEMENT:
299           final IMicroElement eElement = (IMicroElement) aAssertReportChild;
300           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
301           {
302             final String sLocalName = eElement.getLocalName ();
303             if (sLocalName.equals (CSchematronXML.ELEMENT_NAME))
304               ret.addName (readNameFromXML (eElement));
305             else
306               if (sLocalName.equals (CSchematronXML.ELEMENT_VALUE_OF))
307                 ret.addValueOf (readValueOfFromXML (eElement));
308               else
309                 if (sLocalName.equals (CSchematronXML.ELEMENT_EMPH))
310                   ret.addEmph (readEmphFromXML (eElement));
311                 else
312                   if (sLocalName.equals (CSchematronXML.ELEMENT_DIR))
313                     ret.addDir (readDirFromXML (eElement));
314                   else
315                     if (sLocalName.equals (CSchematronXML.ELEMENT_SPAN))
316                       ret.addSpan (readSpanFromXML (eElement));
317                     else
318                       _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
319           }
320           else
321             ret.addForeignElement (eElement.getClone ());
322 
323           break;
324         case COMMENT:
325           // Ignore comments
326           break;
327         default:
328           _warn (ret, "Unsupported child node: " + aAssertReportChild);
329       }
330     });
331     return ret;
332   }
333 
334   /**
335    * Read a &lt;diagnostic&gt; element
336    *
337    * @param eDiagnostic
338    *        The source micro element. Never <code>null</code>.
339    * @return The created domain object. May not be <code>null</code>.
340    */
341   @Nonnull
342   public PSDiagnostic readDiagnosticFromXML (@Nonnull final IMicroElement eDiagnostic)
343   {
344     final PSDiagnosticodel/PSDiagnostic.html#PSDiagnostic">PSDiagnostic ret = new PSDiagnostic ();
345 
346     final PSRichGroupSRichGroup.html#PSRichGroup">PSRichGroup aRichGroup = new PSRichGroup ();
347     eDiagnostic.forAllAttributes ( (sNS, sAttrName, sVal) -> {
348       final String sAttrValue = _getAttributeValue (sVal);
349       if (sAttrName.equals (CSchematronXML.ATTR_ID))
350         ret.setID (sAttrValue);
351       else
352         if (PSRichGroup.isRichAttribute (sAttrName))
353           _handleRichGroup (sAttrName, sAttrValue, aRichGroup);
354         else
355           ret.addForeignAttribute (sAttrName, sAttrValue);
356     });
357     ret.setRich (aRichGroup);
358 
359     eDiagnostic.forAllChildren (aDiagnosticChild -> {
360       switch (aDiagnosticChild.getType ())
361       {
362         case TEXT:
363           ret.addText (((IMicroText) aDiagnosticChild).getNodeValue ());
364           break;
365         case ELEMENT:
366           final IMicroElement eElement = (IMicroElement) aDiagnosticChild;
367           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
368           {
369             final String sLocalName = eElement.getLocalName ();
370             if (sLocalName.equals (CSchematronXML.ELEMENT_VALUE_OF))
371               ret.addValueOf (readValueOfFromXML (eElement));
372             else
373               if (sLocalName.equals (CSchematronXML.ELEMENT_EMPH))
374                 ret.addEmph (readEmphFromXML (eElement));
375               else
376                 if (sLocalName.equals (CSchematronXML.ELEMENT_DIR))
377                   ret.addDir (readDirFromXML (eElement));
378                 else
379                   if (sLocalName.equals (CSchematronXML.ELEMENT_SPAN))
380                     ret.addSpan (readSpanFromXML (eElement));
381                   else
382                     _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
383           }
384           else
385             ret.addForeignElement (eElement.getClone ());
386 
387           break;
388         case COMMENT:
389           // Ignore comments
390           break;
391         default:
392           _warn (ret, "Unsupported child node: " + aDiagnosticChild);
393       }
394     });
395     return ret;
396   }
397 
398   /**
399    * Read a &lt;diagnostics&gt; element
400    *
401    * @param eDiagnostics
402    *        The source micro element. Never <code>null</code>.
403    * @return The created domain object. May not be <code>null</code>.
404    */
405   @Nonnull
406   public PSDiagnostics readDiagnosticsFromXML (@Nonnull final IMicroElement eDiagnostics)
407   {
408     final PSDiagnosticsdel/PSDiagnostics.html#PSDiagnostics">PSDiagnostics ret = new PSDiagnostics ();
409 
410     eDiagnostics.forAllAttributes ( (sNS, sAttrName, sVal) -> {
411       final String sAttrValue = _getAttributeValue (sVal);
412       ret.addForeignAttribute (sAttrName, sAttrValue);
413     });
414 
415     eDiagnostics.forAllChildElements (eDiagnosticsChild -> {
416       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eDiagnosticsChild.getNamespaceURI ()))
417       {
418         if (eDiagnosticsChild.getLocalName ().equals (CSchematronXML.ELEMENT_INCLUDE))
419           ret.addInclude (readIncludeFromXML (eDiagnosticsChild));
420         else
421           if (eDiagnosticsChild.getLocalName ().equals (CSchematronXML.ELEMENT_DIAGNOSTIC))
422             ret.addDiagnostic (readDiagnosticFromXML (eDiagnosticsChild));
423           else
424             _warn (ret, "Unsupported Schematron element '" + eDiagnosticsChild.getLocalName () + "'");
425       }
426       else
427         ret.addForeignElement (eDiagnosticsChild.getClone ());
428     });
429     return ret;
430   }
431 
432   /**
433    * Read a &lt;dir&gt; element
434    *
435    * @param eDir
436    *        The source micro element. Never <code>null</code>.
437    * @return The created domain object. May not be <code>null</code>.
438    */
439   @Nonnull
440   public PSDir readDirFromXML (@Nonnull final IMicroElement eDir)
441   {
442     final PSDir/pure/model/PSDir.html#PSDir">PSDir ret = new PSDir ();
443 
444     eDir.forAllAttributes ( (sNS, sAttrName, sVal) -> {
445       final String sAttrValue = _getAttributeValue (sVal);
446       if (sAttrName.equals (CSchematronXML.ATTR_VALUE))
447         ret.setValue (EDirValue.getFromIDOrNull (sAttrValue));
448       else
449         ret.addForeignAttribute (sAttrName, sAttrValue);
450     });
451 
452     eDir.forAllChildren (aDirChild -> {
453       switch (aDirChild.getType ())
454       {
455         case TEXT:
456           ret.addText (((IMicroText) aDirChild).getNodeValue ());
457           break;
458         case ELEMENT:
459           final IMicroElement eElement = (IMicroElement) aDirChild;
460           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
461           {
462             _warn (ret, "Unsupported Schematron element '" + eElement.getLocalName () + "'");
463           }
464           else
465             ret.addForeignElement (eElement.getClone ());
466 
467           break;
468         case COMMENT:
469           // Ignore comments
470           break;
471         default:
472           _warn (ret, "Unsupported child node: " + aDirChild);
473       }
474     });
475     return ret;
476   }
477 
478   /**
479    * Read an &lt;emph&gt; element
480    *
481    * @param eEmph
482    *        The source micro element. Never <code>null</code>.
483    * @return The created domain object. May not be <code>null</code>.
484    */
485   @Nonnull
486   public PSEmph readEmphFromXML (@Nonnull final IMicroElement eEmph)
487   {
488     final PSEmphpure/model/PSEmph.html#PSEmph">PSEmph ret = new PSEmph ();
489 
490     eEmph.forAllAttributes ( (sNS, sAttrName, sVal) -> {
491       final String sAttrValue = _getAttributeValue (sVal);
492       _warn (ret, "Unsupported attribute '" + sAttrName + "'='" + sAttrValue + "'");
493     });
494 
495     eEmph.forAllChildren (aEmphChild -> {
496       switch (aEmphChild.getType ())
497       {
498         case TEXT:
499           ret.addText (((IMicroText) aEmphChild).getNodeValue ());
500           break;
501         case ELEMENT:
502           final IMicroElement eElement = (IMicroElement) aEmphChild;
503           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
504           {
505             _warn (ret, "Unsupported Schematron element '" + eElement.getLocalName () + "'");
506           }
507           else
508             _warn (ret, "Unsupported namespace URI '" + eElement.getNamespaceURI () + "'");
509 
510           break;
511         case COMMENT:
512           // Ignore comments
513           break;
514         default:
515           _warn (ret, "Unsupported child node: " + aEmphChild);
516       }
517     });
518     return ret;
519   }
520 
521   /**
522    * Read an &lt;extends&gt; element
523    *
524    * @param eExtends
525    *        The source micro element. Never <code>null</code>.
526    * @return The created domain object. May not be <code>null</code>.
527    */
528   @Nonnull
529   public PSExtends readExtendsFromXML (@Nonnull final IMicroElement eExtends)
530   {
531     final PSExtendse/model/PSExtends.html#PSExtends">PSExtends ret = new PSExtends ();
532 
533     eExtends.forAllAttributes ( (sNS, sAttrName, sVal) -> {
534       final String sAttrValue = _getAttributeValue (sVal);
535       if (sAttrName.equals (CSchematronXML.ATTR_RULE))
536         ret.setRule (sAttrValue);
537       else
538         ret.addForeignAttribute (sAttrName, sAttrValue);
539     });
540 
541     eExtends.forAllChildElements (eChild -> {
542       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eChild.getNamespaceURI ()))
543       {
544         _warn (ret, "Unsupported Schematron element '" + eChild.getLocalName () + "'");
545       }
546       else
547         _warn (ret, "Unsupported namespace URI '" + eChild.getNamespaceURI () + "'");
548     });
549     return ret;
550   }
551 
552   /**
553    * Read an &lt;include&gt; element
554    *
555    * @param eInclude
556    *        The source micro element. Never <code>null</code>.
557    * @return The created domain object. May not be <code>null</code>.
558    */
559   @Nonnull
560   public PSInclude readIncludeFromXML (@Nonnull final IMicroElement eInclude)
561   {
562     final PSIncludee/model/PSInclude.html#PSInclude">PSInclude ret = new PSInclude ();
563 
564     eInclude.forAllAttributes ( (sNS, sAttrName, sVal) -> {
565       final String sAttrValue = _getAttributeValue (sVal);
566       if (sAttrName.equals (CSchematronXML.ATTR_HREF))
567         ret.setHref (sAttrValue);
568       else
569         _warn (ret, "Unsupported attribute '" + sAttrName + "'='" + sAttrValue + "'");
570     });
571 
572     eInclude.forAllChildElements (eValueOfChild -> {
573       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eValueOfChild.getNamespaceURI ()))
574       {
575         _warn (ret, "Unsupported Schematron element '" + eValueOfChild.getLocalName () + "'");
576       }
577       else
578         _warn (ret, "Unsupported namespace URI '" + eValueOfChild.getNamespaceURI () + "'");
579     });
580     return ret;
581   }
582 
583   /**
584    * Read a &lt;let&gt; element
585    *
586    * @param eLet
587    *        The source micro element. Never <code>null</code>.
588    * @return The created domain object. May not be <code>null</code>.
589    */
590   @Nonnull
591   public PSLet readLetFromXML (@Nonnull final IMicroElement eLet)
592   {
593     final PSLet/pure/model/PSLet.html#PSLet">PSLet ret = new PSLet ();
594 
595     eLet.forAllAttributes ( (sNS, sAttrName, sVal) -> {
596       final String sAttrValue = _getAttributeValue (sVal);
597       if (sAttrName.equals (CSchematronXML.ATTR_NAME))
598         ret.setName (sAttrValue);
599       else
600         if (sAttrName.equals (CSchematronXML.ATTR_VALUE))
601           ret.setValue (sAttrValue);
602         else
603           _warn (ret, "Unsupported attribute '" + sAttrName + "'='" + sAttrValue + "'");
604     });
605 
606     eLet.forAllChildElements (eLetChild -> {
607       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eLetChild.getNamespaceURI ()))
608       {
609         _warn (ret, "Unsupported Schematron element '" + eLetChild.getLocalName () + "'");
610       }
611       else
612         _warn (ret, "Unsupported namespace URI '" + eLetChild.getNamespaceURI () + "'");
613     });
614     return ret;
615   }
616 
617   /**
618    * Read a &lt;name&gt; element
619    *
620    * @param eName
621    *        The source micro element. Never <code>null</code>.
622    * @return The created domain object. May not be <code>null</code>.
623    */
624   @Nonnull
625   public PSName readNameFromXML (@Nonnull final IMicroElement eName)
626   {
627     final PSNamepure/model/PSName.html#PSName">PSName ret = new PSName ();
628 
629     eName.forAllAttributes ( (sNS, sAttrName, sVal) -> {
630       final String sAttrValue = _getAttributeValue (sVal);
631       if (sAttrName.equals (CSchematronXML.ATTR_PATH))
632         ret.setPath (sAttrValue);
633       else
634         ret.addForeignAttribute (sAttrName, sAttrValue);
635     });
636 
637     eName.forAllChildElements (eNameChild -> {
638       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eNameChild.getNamespaceURI ()))
639       {
640         _warn (ret, "Unsupported Schematron element '" + eNameChild.getLocalName () + "'");
641       }
642       else
643         _warn (ret, "Unsupported namespace URI '" + eNameChild.getNamespaceURI () + "'");
644     });
645     return ret;
646   }
647 
648   /**
649    * Read a &lt;ns&gt; element
650    *
651    * @param eNS
652    *        The source micro element. Never <code>null</code>.
653    * @return The created domain object. May not be <code>null</code>.
654    */
655   @Nonnull
656   public PSNS readNSFromXML (@Nonnull final IMicroElement eNS)
657   {
658     final PSNSn/pure/model/PSNS.html#PSNS">PSNS ret = new PSNS ();
659 
660     eNS.forAllAttributes ( (sNS, sAttrName, sVal) -> {
661       final String sAttrValue = _getAttributeValue (sVal);
662       if (sAttrName.equals (CSchematronXML.ATTR_URI))
663         ret.setUri (sAttrValue);
664       else
665         if (sAttrName.equals (CSchematronXML.ATTR_PREFIX))
666           ret.setPrefix (sAttrValue);
667         else
668           ret.addForeignAttribute (sAttrName, sAttrValue);
669     });
670 
671     eNS.forAllChildElements (eLetChild -> {
672       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eLetChild.getNamespaceURI ()))
673       {
674         _warn (ret, "Unsupported Schematron element '" + eLetChild.getLocalName () + "'");
675       }
676       else
677         _warn (ret, "Unsupported namespace URI '" + eLetChild.getNamespaceURI () + "'");
678     });
679     return ret;
680   }
681 
682   /**
683    * Read a &lt;p&gt; element
684    *
685    * @param eP
686    *        The source micro element. Never <code>null</code>.
687    * @return The created domain object. May not be <code>null</code>.
688    */
689   @Nonnull
690   public PSP readPFromXML (@Nonnull final IMicroElement eP)
691   {
692     final PSPon/pure/model/PSP.html#PSP">PSP ret = new PSP ();
693     eP.forAllAttributes ( (sNS, sAttrName, sVal) -> {
694       final String sAttrValue = _getAttributeValue (sVal);
695       if (sAttrName.equals (CSchematronXML.ATTR_ID))
696         ret.setID (sAttrValue);
697       else
698         if (sAttrName.equals (CSchematronXML.ATTR_CLASS))
699           ret.setClazz (sAttrValue);
700         else
701           if (sAttrName.equals (CSchematronXML.ATTR_ICON))
702             ret.setIcon (sAttrValue);
703           else
704             ret.addForeignAttribute (sAttrName, sAttrValue);
705     });
706 
707     eP.forAllChildren (aChild -> {
708       switch (aChild.getType ())
709       {
710         case TEXT:
711           ret.addText (((IMicroText) aChild).getNodeValue ());
712           break;
713         case ELEMENT:
714           final IMicroElement eElement = (IMicroElement) aChild;
715           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
716           {
717             final String sLocalName = eElement.getLocalName ();
718             if (sLocalName.equals (CSchematronXML.ELEMENT_DIR))
719               ret.addDir (readDirFromXML (eElement));
720             else
721               if (sLocalName.equals (CSchematronXML.ELEMENT_EMPH))
722                 ret.addEmph (readEmphFromXML (eElement));
723               else
724                 if (sLocalName.equals (CSchematronXML.ELEMENT_SPAN))
725                   ret.addSpan (readSpanFromXML (eElement));
726                 else
727                   _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
728           }
729           else
730             ret.addForeignElement (eElement.getClone ());
731 
732           break;
733         case COMMENT:
734           // Ignore comments
735           break;
736         default:
737           _warn (ret, "Unsupported child node: " + aChild);
738       }
739     });
740     return ret;
741   }
742 
743   /**
744    * Read a &lt;param&gt; element
745    *
746    * @param eParam
747    *        The source micro element. Never <code>null</code>.
748    * @return The created domain object. May not be <code>null</code>.
749    */
750   @Nonnull
751   public PSParam readParamFromXML (@Nonnull final IMicroElement eParam)
752   {
753     final PSParamure/model/PSParam.html#PSParam">PSParam ret = new PSParam ();
754 
755     eParam.forAllAttributes ( (sNS, sAttrName, sVal) -> {
756       final String sAttrValue = _getAttributeValue (sVal);
757       if (sAttrName.equals (CSchematronXML.ATTR_NAME))
758         ret.setName (sAttrValue);
759       else
760         if (sAttrName.equals (CSchematronXML.ATTR_VALUE))
761           ret.setValue (sAttrValue);
762         else
763           _warn (ret, "Unsupported attribute '" + sAttrName + "'='" + sAttrValue + "'");
764     });
765 
766     eParam.forAllChildElements (eParamChild -> {
767       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eParamChild.getNamespaceURI ()))
768       {
769         _warn (ret, "Unsupported Schematron element '" + eParamChild.getLocalName () + "'");
770       }
771       else
772         _warn (ret, "Unsupported namespace URI '" + eParamChild.getNamespaceURI () + "'");
773     });
774     return ret;
775   }
776 
777   /**
778    * Read a &lt;pattern&gt; element
779    *
780    * @param ePattern
781    *        The source micro element. Never <code>null</code>.
782    * @return The created domain object. May not be <code>null</code>.
783    */
784   @Nonnull
785   public PSPattern readPatternFromXML (@Nonnull final IMicroElement ePattern)
786   {
787     final PSPatterne/model/PSPattern.html#PSPattern">PSPattern ret = new PSPattern ();
788 
789     final PSRichGroupSRichGroup.html#PSRichGroup">PSRichGroup aRichGroup = new PSRichGroup ();
790     ePattern.forAllAttributes ( (sNS, sAttrName, sVal) -> {
791       final String sAttrValue = _getAttributeValue (sVal);
792       if (sAttrName.equals (CSchematronXML.ATTR_ABSTRACT))
793         ret.setAbstract (StringParser.parseBool (sAttrValue));
794       else
795         if (sAttrName.equals (CSchematronXML.ATTR_ID))
796           ret.setID (sAttrValue);
797         else
798           if (sAttrName.equals (CSchematronXML.ATTR_IS_A))
799             ret.setIsA (sAttrValue);
800           else
801             if (PSRichGroup.isRichAttribute (sAttrName))
802               _handleRichGroup (sAttrName, sAttrValue, aRichGroup);
803             else
804               ret.addForeignAttribute (sAttrName, sAttrValue);
805     });
806     ret.setRich (aRichGroup);
807 
808     ePattern.forAllChildElements (ePatternChild -> {
809       if (CSchematron.NAMESPACE_SCHEMATRON.equals (ePatternChild.getNamespaceURI ()))
810       {
811         if (ePatternChild.getLocalName ().equals (CSchematronXML.ELEMENT_INCLUDE))
812           ret.addInclude (readIncludeFromXML (ePatternChild));
813         else
814           if (ePatternChild.getLocalName ().equals (CSchematronXML.ELEMENT_TITLE))
815             ret.setTitle (readTitleFromXML (ePatternChild));
816           else
817             if (ePatternChild.getLocalName ().equals (CSchematronXML.ELEMENT_P))
818               ret.addP (readPFromXML (ePatternChild));
819             else
820               if (ePatternChild.getLocalName ().equals (CSchematronXML.ELEMENT_LET))
821                 ret.addLet (readLetFromXML (ePatternChild));
822               else
823                 if (ePatternChild.getLocalName ().equals (CSchematronXML.ELEMENT_RULE))
824                   ret.addRule (readRuleFromXML (ePatternChild));
825                 else
826                   if (ePatternChild.getLocalName ().equals (CSchematronXML.ELEMENT_PARAM))
827                     ret.addParam (readParamFromXML (ePatternChild));
828                   else
829                     _warn (ret,
830                            "Unsupported Schematron element '" +
831                                 ePatternChild.getLocalName () +
832                                 "' in " +
833                                 ret.toString ());
834       }
835       else
836         ret.addForeignElement (ePatternChild.getClone ());
837     });
838     return ret;
839   }
840 
841   /**
842    * Read a &lt;phase&gt; element
843    *
844    * @param ePhase
845    *        The source micro element. Never <code>null</code>.
846    * @return The created domain object. May not be <code>null</code>.
847    */
848   @Nonnull
849   public PSPhase readPhaseFromXML (@Nonnull final IMicroElement ePhase)
850   {
851     final PSPhaseure/model/PSPhase.html#PSPhase">PSPhase ret = new PSPhase ();
852 
853     final PSRichGroupSRichGroup.html#PSRichGroup">PSRichGroup aRichGroup = new PSRichGroup ();
854     ePhase.forAllAttributes ( (sNS, sAttrName, sVal) -> {
855       final String sAttrValue = _getAttributeValue (sVal);
856       if (sAttrName.equals (CSchematronXML.ATTR_ID))
857         ret.setID (sAttrValue);
858       else
859         if (PSRichGroup.isRichAttribute (sAttrName))
860           _handleRichGroup (sAttrName, sAttrValue, aRichGroup);
861         else
862           ret.addForeignAttribute (sAttrName, sAttrValue);
863     });
864     ret.setRich (aRichGroup);
865 
866     ePhase.forAllChildElements (ePhaseChild -> {
867       if (CSchematron.NAMESPACE_SCHEMATRON.equals (ePhaseChild.getNamespaceURI ()))
868       {
869         if (ePhaseChild.getLocalName ().equals (CSchematronXML.ELEMENT_INCLUDE))
870           ret.addInclude (readIncludeFromXML (ePhaseChild));
871         else
872           if (ePhaseChild.getLocalName ().equals (CSchematronXML.ELEMENT_P))
873             ret.addP (readPFromXML (ePhaseChild));
874           else
875             if (ePhaseChild.getLocalName ().equals (CSchematronXML.ELEMENT_LET))
876               ret.addLet (readLetFromXML (ePhaseChild));
877             else
878               if (ePhaseChild.getLocalName ().equals (CSchematronXML.ELEMENT_ACTIVE))
879                 ret.addActive (readActiveFromXML (ePhaseChild));
880               else
881                 _warn (ret, "Unsupported Schematron element '" + ePhaseChild.getLocalName () + "'");
882       }
883       else
884         ret.addForeignElement (ePhaseChild.getClone ());
885     });
886     return ret;
887   }
888 
889   /**
890    * Read a &lt;rule&gt; element
891    *
892    * @param eRule
893    *        The source micro element. Never <code>null</code>.
894    * @return The created domain object. May not be <code>null</code>.
895    */
896   @Nonnull
897   public PSRule readRuleFromXML (@Nonnull final IMicroElement eRule)
898   {
899     final PSRulepure/model/PSRule.html#PSRule">PSRule ret = new PSRule ();
900 
901     final PSRichGroupSRichGroup.html#PSRichGroup">PSRichGroup aRichGroup = new PSRichGroup ();
902     final PSLinkableGroupeGroup.html#PSLinkableGroup">PSLinkableGroup aLinkableGroup = new PSLinkableGroup ();
903     eRule.forAllAttributes ( (sNS, sAttrName, sVal) -> {
904       final String sAttrValue = _getAttributeValue (sVal);
905       if (sAttrName.equals (CSchematronXML.ATTR_FLAG))
906         ret.setFlag (sAttrValue);
907       else
908         if (sAttrName.equals (CSchematronXML.ATTR_ABSTRACT))
909           ret.setAbstract (StringParser.parseBool (sAttrValue));
910         else
911           if (sAttrName.equals (CSchematronXML.ATTR_CONTEXT))
912             ret.setContext (sAttrValue);
913           else
914             if (sAttrName.equals (CSchematronXML.ATTR_ID))
915               ret.setID (sAttrValue);
916             else
917               if (PSRichGroup.isRichAttribute (sAttrName))
918                 _handleRichGroup (sAttrName, sAttrValue, aRichGroup);
919               else
920                 if (PSLinkableGroup.isLinkableAttribute (sAttrName))
921                   _handleLinkableGroup (sAttrName, sAttrValue, aLinkableGroup);
922                 else
923                   ret.addForeignAttribute (sAttrName, sAttrValue);
924     });
925     ret.setRich (aRichGroup);
926     ret.setLinkable (aLinkableGroup);
927 
928     eRule.forAllChildElements (eRuleChild -> {
929       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eRuleChild.getNamespaceURI ()))
930       {
931         final String sLocalName = eRuleChild.getLocalName ();
932         if (sLocalName.equals (CSchematronXML.ELEMENT_INCLUDE))
933           ret.addInclude (readIncludeFromXML (eRuleChild));
934         else
935           if (sLocalName.equals (CSchematronXML.ELEMENT_LET))
936             ret.addLet (readLetFromXML (eRuleChild));
937           else
938             if (sLocalName.equals (CSchematronXML.ELEMENT_ASSERT) || sLocalName.equals (CSchematronXML.ELEMENT_REPORT))
939               ret.addAssertReport (readAssertReportFromXML (eRuleChild));
940             else
941               if (sLocalName.equals (CSchematronXML.ELEMENT_EXTENDS))
942                 ret.addExtends (readExtendsFromXML (eRuleChild));
943               else
944                 _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
945       }
946       else
947         ret.addForeignElement (eRuleChild.getClone ());
948     });
949     return ret;
950   }
951 
952   /**
953    * Parse the Schematron into a pure Java object. This method makes no
954    * assumptions on the validity of the document!
955    *
956    * @param eSchema
957    *        The XML element to use. May not be <code>null</code>.
958    * @return The created {@link PSSchema} object or <code>null</code> in case of
959    *         <code>null</code> document or a fatal error.
960    * @throws SchematronReadException
961    *         If reading fails
962    */
963   @Nonnull
964   public PSSchema readSchemaFromXML (@Nonnull final IMicroElement eSchema) throws SchematronReadException
965   {
966     ValueEnforcer.notNull (eSchema, "Schema");
967     if (!CSchematron.NAMESPACE_SCHEMATRON.equals (eSchema.getNamespaceURI ()))
968       throw new SchematronReadException (m_aResource, "The passed element is not an ISO Schematron element!");
969 
970     final PSSchemare/model/PSSchema.html#PSSchema">PSSchema ret = new PSSchema (m_aResource);
971     final PSRichGroupSRichGroup.html#PSRichGroup">PSRichGroup aRichGroup = new PSRichGroup ();
972     eSchema.forAllAttributes ( (sNS, sAttrName, sVal) -> {
973       final String sAttrValue = _getAttributeValue (sVal);
974       if (sAttrName.equals (CSchematronXML.ATTR_ID))
975         ret.setID (sAttrValue);
976       else
977         if (sAttrName.equals (CSchematronXML.ATTR_SCHEMA_VERSION))
978           ret.setSchemaVersion (sAttrValue);
979         else
980           if (sAttrName.equals (CSchematronXML.ATTR_DEFAULT_PHASE))
981             ret.setDefaultPhase (sAttrValue);
982           else
983             if (sAttrName.equals (CSchematronXML.ATTR_QUERY_BINDING))
984               ret.setQueryBinding (sAttrValue);
985             else
986               if (PSRichGroup.isRichAttribute (sAttrName))
987                 _handleRichGroup (sAttrName, sAttrValue, aRichGroup);
988               else
989                 ret.addForeignAttribute (sAttrName, sAttrValue);
990     });
991     ret.setRich (aRichGroup);
992 
993     eSchema.forAllChildElements (eSchemaChild -> {
994       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eSchemaChild.getNamespaceURI ()))
995       {
996         if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_INCLUDE))
997           ret.addInclude (readIncludeFromXML (eSchemaChild));
998         else
999           if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_TITLE))
1000             ret.setTitle (readTitleFromXML (eSchemaChild));
1001           else
1002             if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_NS))
1003               ret.addNS (readNSFromXML (eSchemaChild));
1004             else
1005               if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_P))
1006               {
1007                 final PSP aP = readPFromXML (eSchemaChild);
1008                 if (ret.hasNoPatterns ())
1009                   ret.addStartP (aP);
1010                 else
1011                   ret.addEndP (aP);
1012               }
1013               else
1014                 if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_LET))
1015                   ret.addLet (readLetFromXML (eSchemaChild));
1016                 else
1017                   if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_PHASE))
1018                     ret.addPhase (readPhaseFromXML (eSchemaChild));
1019                   else
1020                     if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_PATTERN))
1021                       ret.addPattern (readPatternFromXML (eSchemaChild));
1022                     else
1023                       if (eSchemaChild.getLocalName ().equals (CSchematronXML.ELEMENT_DIAGNOSTICS))
1024                         ret.setDiagnostics (readDiagnosticsFromXML (eSchemaChild));
1025                       else
1026                         _warn (ret, "Unsupported Schematron element '" + eSchemaChild.getLocalName () + "'");
1027       }
1028       else
1029         ret.addForeignElement (eSchemaChild.getClone ());
1030     });
1031     return ret;
1032   }
1033 
1034   /**
1035    * Read a &lt;span&gt; element
1036    *
1037    * @param eSpan
1038    *        The source micro element. Never <code>null</code>.
1039    * @return The created domain object. May not be <code>null</code>.
1040    */
1041   @Nonnull
1042   public PSSpan readSpanFromXML (@Nonnull final IMicroElement eSpan)
1043   {
1044     final PSSpanpure/model/PSSpan.html#PSSpan">PSSpan ret = new PSSpan ();
1045 
1046     eSpan.forAllAttributes ( (sNS, sAttrName, sVal) -> {
1047       final String sAttrValue = _getAttributeValue (sVal);
1048       if (sAttrName.equals (CSchematronXML.ATTR_CLASS))
1049         ret.setClazz (sAttrValue);
1050       else
1051         ret.addForeignAttribute (sAttrName, sAttrValue);
1052     });
1053 
1054     eSpan.forAllChildren (aSpanChild -> {
1055       switch (aSpanChild.getType ())
1056       {
1057         case TEXT:
1058           ret.addText (((IMicroText) aSpanChild).getNodeValue ());
1059           break;
1060         case ELEMENT:
1061           final IMicroElement eElement = (IMicroElement) aSpanChild;
1062           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
1063           {
1064             _warn (ret, "Unsupported Schematron element '" + eElement.getLocalName () + "'");
1065           }
1066           else
1067             ret.addForeignElement (eElement.getClone ());
1068 
1069           break;
1070         case COMMENT:
1071           // Ignore comments
1072           break;
1073         default:
1074           _warn (ret, "Unsupported child node: " + aSpanChild);
1075       }
1076     });
1077     return ret;
1078   }
1079 
1080   /**
1081    * Read a &lt;title&gt; element
1082    *
1083    * @param eTitle
1084    *        The source micro element. Never <code>null</code>.
1085    * @return The created domain object. May not be <code>null</code>.
1086    */
1087   @Nonnull
1088   public PSTitle readTitleFromXML (@Nonnull final IMicroElement eTitle)
1089   {
1090     final PSTitleure/model/PSTitle.html#PSTitle">PSTitle ret = new PSTitle ();
1091 
1092     eTitle.forAllAttributes ( (sNS, sAttrName, sVal) -> {
1093       final String sAttrValue = _getAttributeValue (sVal);
1094       _warn (ret, "Unsupported attribute '" + sAttrName + "'='" + sAttrValue + "'");
1095     });
1096 
1097     eTitle.forAllChildren (aTitleChild -> {
1098       switch (aTitleChild.getType ())
1099       {
1100         case TEXT:
1101           ret.addText (((IMicroText) aTitleChild).getNodeValue ());
1102           break;
1103         case ELEMENT:
1104           final IMicroElement eElement = (IMicroElement) aTitleChild;
1105           if (CSchematron.NAMESPACE_SCHEMATRON.equals (eElement.getNamespaceURI ()))
1106           {
1107             final String sLocalName = eElement.getLocalName ();
1108             if (sLocalName.equals (CSchematronXML.ELEMENT_DIR))
1109               ret.addDir (readDirFromXML (eElement));
1110             else
1111               _warn (ret, "Unsupported Schematron element '" + sLocalName + "'");
1112           }
1113           else
1114             _warn (ret, "Unsupported namespace URI '" + eElement.getNamespaceURI () + "'");
1115 
1116           break;
1117         case COMMENT:
1118           // Ignore comments
1119           break;
1120         default:
1121           _warn (ret, "Unsupported child node: " + aTitleChild);
1122       }
1123     });
1124     return ret;
1125   }
1126 
1127   /**
1128    * Read a &lt;value-of&gt; element
1129    *
1130    * @param eValueOf
1131    *        The source micro element. Never <code>null</code>.
1132    * @return The created domain object. May not be <code>null</code>.
1133    */
1134   @Nonnull
1135   public PSValueOf readValueOfFromXML (@Nonnull final IMicroElement eValueOf)
1136   {
1137     final PSValueOfe/model/PSValueOf.html#PSValueOf">PSValueOf ret = new PSValueOf ();
1138 
1139     eValueOf.forAllAttributes ( (sNS, sAttrName, sVal) -> {
1140       final String sAttrValue = _getAttributeValue (sVal);
1141       if (sAttrName.equals (CSchematronXML.ATTR_SELECT))
1142         ret.setSelect (sAttrValue);
1143       else
1144         ret.addForeignAttribute (sAttrName, sAttrValue);
1145     });
1146 
1147     eValueOf.forAllChildElements (eValueOfChild -> {
1148       if (CSchematron.NAMESPACE_SCHEMATRON.equals (eValueOfChild.getNamespaceURI ()))
1149       {
1150         _warn (ret, "Unsupported Schematron element '" + eValueOfChild.getLocalName () + "'");
1151       }
1152       else
1153         _warn (ret, "Unsupported namespace URI '" + eValueOfChild.getNamespaceURI () + "'");
1154     });
1155     return ret;
1156   }
1157 
1158   /**
1159    * Read the schema from the resource supplied in the constructor. First all
1160    * includes are resolved and than {@link #readSchemaFromXML(IMicroElement)} is
1161    * called.
1162    *
1163    * @return The read {@link PSSchema}.
1164    * @throws SchematronReadException
1165    *         If reading fails
1166    */
1167   @Nonnull
1168   public PSSchema readSchema () throws SchematronReadException
1169   {
1170     // Resolve all includes as the first action
1171     final SAXReaderSettings aSettings = new SAXReaderSettings ().setEntityResolver (m_aEntityResolver);
1172 
1173     final IMicroDocument aDoc = SchematronHelper.getWithResolvedSchematronIncludes (m_aResource,
1174                                                                                     aSettings,
1175                                                                                     m_aErrorHandler);
1176     if (aDoc == null || aDoc.getDocumentElement () == null)
1177       throw new SchematronReadException (m_aResource,
1178                                          "Failed to resolve includes in Schematron resource " + m_aResource);
1179 
1180     if (SchematronDebug.isShowResolvedSourceSchematron ())
1181       LOGGER.info ("Resolved source Schematron:\n" + MicroWriter.getNodeAsString (aDoc));
1182 
1183     return readSchemaFromXML (aDoc.getDocumentElement ());
1184   }
1185 
1186   @Override
1187   public String toString ()
1188   {
1189     return new ToStringGenerator (this).append ("resource", m_aResource)
1190                                        .append ("errorHandler", m_aErrorHandler)
1191                                        .getToString ();
1192   }
1193 }