View Javadoc
1   package org.apache.maven.doxia.module.docbook;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.PrintWriter;
23  import java.io.StringWriter;
24  import java.io.Writer;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Locale;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.Stack;
32  import java.util.StringTokenizer;
33  import java.util.TreeSet;
34  
35  import javax.swing.text.MutableAttributeSet;
36  import javax.swing.text.SimpleAttributeSet;
37  
38  import org.apache.maven.doxia.sink.Sink;
39  import org.apache.maven.doxia.sink.SinkEventAttributes;
40  import org.apache.maven.doxia.sink.impl.AbstractXmlSink;
41  import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
42  import org.apache.maven.doxia.util.DoxiaUtils;
43  import org.codehaus.plexus.util.FileUtils;
44  
45  import static org.apache.maven.doxia.util.HtmlTools.escapeHTML;
46  
47  /**
48   * <a href="http://www.oasis-open.org/docbook">Docbook</a> Sink implementation.
49   * <br>
50   * It uses the Docbook v4.4 DTD <a href="http://www.oasis-open.org/docbook/sgml/4.4/docbookx.dtd">
51   * http://www.oasis-open.org/docbook/sgml/4.4/docbookx.dtd</a>.
52   *
53   * @since 1.0
54   */
55  public class DocBookSink
56      extends AbstractXmlSink
57      implements DocbookMarkup, SimplifiedDocbookMarkup
58  {
59      /** DocBook V4.4 SGML public id: "-//OASIS//DTD DocBook V4.4//EN"
60       * @deprecated since 1.1, use {@link DocbookMarkup#DEFAULT_SGML_PUBLIC_ID} instead of. */
61      public static final String DEFAULT_SGML_PUBLIC_ID = DocbookMarkup.DEFAULT_SGML_PUBLIC_ID;
62  
63      /** DocBook XML V4.4 XML public id: "-//OASIS//DTD DocBook XML V4.4//EN"
64       * @deprecated since 1.1, use {@link DocbookMarkup#DEFAULT_XML_PUBLIC_ID} instead of. */
65      public static final String DEFAULT_XML_PUBLIC_ID = DocbookMarkup.DEFAULT_XML_PUBLIC_ID;
66  
67      /** DocBook XML V4.4 XML system id: "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"
68       * @deprecated since 1.1, use {@link DocbookMarkup#DEFAULT_XML_SYSTEM_ID} instead of. */
69      public static final String DEFAULT_XML_SYSTEM_ID = DocbookMarkup.DEFAULT_XML_SYSTEM_ID;
70  
71      /** DocBook XML V4.4 SGML system id: "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd"
72       * @deprecated since 1.1, use {@link DocbookMarkup#DEFAULT_SGML_SYSTEM_ID} instead of. */
73      public static final String DEFAULT_SGML_SYSTEM_ID = DocbookMarkup.DEFAULT_SGML_SYSTEM_ID;
74  
75      /** The output writer. */
76      private PrintWriter out;
77  
78      /** xmlMode. */
79      private boolean xmlMode = false;
80  
81      /** styleSheet. */
82      private String styleSheet = null;
83  
84      /** language. */
85      private String lang = null;
86  
87      /** publicId. */
88      private String publicId = null;
89  
90      /** systemId. */
91      private String systemId = null;
92  
93      /** italicBegin. */
94      private String italicBeginTag;
95  
96      /** italicEnd. */
97      private String italicEndTag;
98  
99      /** boldBegin. */
100     private String boldBeginTag;
101 
102     /** boldEnd. */
103     private String boldEndTag;
104 
105     /** monospacedBegin. */
106     private String monospacedBeginTag;
107 
108     /** monospacedEnd. */
109     private String monospacedEndTag;
110 
111     /** horizontalRule. */
112     private String horizontalRuleElement;
113 
114     /** pageBreak. */
115     private String pageBreakElement;
116 
117     /** lineBreak. */
118     private String lineBreakElement;
119 
120     /** An image source file. */
121     private String graphicsFileName;
122 
123     /** hasTitle. */
124     private boolean hasTitle;
125 
126     /** authorDate. */
127     private boolean authorDateFlag;
128 
129     /** verbatim. */
130     private boolean verbatimFlag;
131 
132     /** externalLink. */
133     private boolean externalLinkFlag;
134 
135     /** tableHasCaption. */
136     private boolean tableHasCaption;
137 
138     /** Used for table rows. */
139     private PrintWriter savedOut;
140 
141     /** tableRows. */
142     private String tableRows;
143 
144     /** tableRows writer. */
145     private StringWriter tableRowsWriter;
146 
147     /** tableHasGrid. */
148     private boolean tableHasGrid;
149 
150     private boolean skip;
151 
152     private boolean paragraph;
153 
154     private String encoding;
155 
156     /** Keep track of the closing tags for inline events. */
157     protected Stack<List<String>> inlineStack = new Stack<>();
158 
159     /** Map of warn messages with a String as key to describe the error type and a Set as value.
160      * Using to reduce warn messages. */
161     private Map<String, Set<String>> warnMessages;
162 
163     /**
164      * Constructor, initialize the Writer.
165      *
166      * @param writer not null writer to write the result. <b>Should</b> be an UTF-8 Writer.
167      * You could use <code>newXmlWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}.
168      */
169     protected DocBookSink( Writer writer )
170     {
171         this( writer, null );
172     }
173 
174     /**
175      * Constructor, initialize the Writer and tells which encoding is used.
176      *
177      * @param writer not null writer to write the result.
178      * @param encoding the encoding used, that should be written to the generated HTML content
179      * if not <code>null</code>.
180      */
181     protected DocBookSink( Writer writer, String encoding )
182     {
183         this.out = new PrintWriter( writer );
184         this.encoding = encoding;
185 
186         setItalicElement( "<emphasis>" );
187         setBoldElement( "<emphasis role=\"bold\">" );
188         setMonospacedElement( "<literal>" );
189         setHorizontalRuleElement( "<!-- HR -->" );
190         setPageBreakElement( "<!-- PB -->" );
191         setLineBreakElement( "<!-- LB -->" );
192     }
193 
194     /**
195      * Constructor, initialize the Writer and tells which encoding and languageId are used.
196      *
197      * @param writer not null writer to write the result.
198      * @param encoding the encoding used, that should be written to the generated HTML content
199      * if not <code>null</code>.
200      * @param languageId language identifier for the root element as defined by
201      * <a href="ftp://ftp.isi.edu/in-notes/bcp/bcp47.txt">IETF BCP 47</a>, Tags for the Identification of Languages;
202      * in addition, the empty string may be specified.
203      * @since 1.1
204      */
205     protected DocBookSink( Writer writer, String encoding, String languageId )
206     {
207         this( writer, encoding );
208 
209         this.lang = languageId;
210     }
211 
212     /**
213      * <p>escapeSGML</p>
214      *
215      * @param text The text to escape.
216      * @param xmlMode xmlMode.
217      * @return The escaped text.
218      * @deprecated Use HtmlTools#escapeHTML(String,boolean).
219      */
220     public static String escapeSGML( String text, boolean xmlMode )
221     {
222         return escapeHTML( text, xmlMode );
223     }
224 
225     /**
226      * Sets the xml mode.
227      *
228      * @param mode the mode to set.
229      * @deprecated xml mode is not used.
230      */
231     public void setXMLMode( boolean mode )
232     {
233         this.xmlMode = mode;
234     }
235 
236     /**
237      * Returns the current xmlMode.
238      *
239      * @return the current xmlMode.
240      * @deprecated xml mode is not used.
241      */
242     public boolean isXMLMode()
243     {
244         return xmlMode;
245     }
246 
247     /**
248      * Sets the encoding. The encoding specified here must be consistent with then encoding
249      * used in the Writer used by this DocBookSink instance.
250      *
251      * @param enc the encoding to set.
252      */
253     public void setEncoding( String enc )
254     {
255         encoding = enc;
256     }
257 
258     /**
259      * Returns the encoding.
260      *
261      * @return the encoding set (can be <code>null</code>).
262      */
263     public String getEncoding()
264     {
265         return encoding;
266     }
267 
268     /**
269      * Sets the styleSheet.
270      *
271      * @param sheet the styleSheet to set.
272      */
273     public void setStyleSheet( String sheet )
274     {
275         this.styleSheet = sheet;
276     }
277 
278     /**
279      * Returns the current styleSheet.
280      *
281      * @return the current styleSheet.
282      */
283     public String getStyleSheet()
284     {
285         return styleSheet;
286     }
287 
288     /**
289      * Sets the publicId.
290      *
291      * @param id the publicId to set.
292      */
293     public void setPublicId( String id )
294     {
295         this.publicId = id;
296     }
297 
298     /**
299      * Returns the current publicId.
300      *
301      * @return the current publicId.
302      */
303     public String getPublicId()
304     {
305         return publicId;
306     }
307 
308     /**
309      * Sets the systemId.
310      *
311      * @param id the systemId to set.
312      */
313     public void setSystemId( String id )
314     {
315         this.systemId = id;
316     }
317 
318     /**
319      * Returns the current systemId.
320      *
321      * @return the current systemId.
322      */
323     public String getSystemId()
324     {
325         return systemId;
326     }
327 
328     /**
329      * Sets the language.
330      *
331      * @param language the language to set.
332      */
333     public void setLanguage( String language )
334     {
335         this.lang = language;
336     }
337 
338     /**
339      * Returns the current language.
340      *
341      * @return the current language.
342      */
343     public String getLanguage()
344     {
345         return lang;
346     }
347 
348     /**
349      * Sets the current italicBeginTag and constructs the corresponding end tag from it.
350      *
351      * @param tag the tag to set. If tag is null, the empty string is used.
352      */
353     public void setItalicElement( String tag )
354     {
355         if ( tag == null )
356         {
357             tag = "";
358         }
359         this.italicBeginTag = tag;
360         italicEndTag = makeEndTag( italicBeginTag );
361     }
362 
363     /**
364      * Constructs the corresponding end tag from the given begin tag.
365      *
366      * @param beginTag the begin tag to set. If null, the empty string is returned.
367      * @return the corresponding end tag.
368      */
369     private String makeEndTag( String beginTag )
370     {
371         int length = beginTag.length();
372         if ( length == 0 )
373         {
374             return "";
375         }
376 
377         if ( beginTag.charAt( 0 ) != '<' || beginTag.charAt( length - 1 ) != '>' )
378         {
379             throw new IllegalArgumentException( "'" + beginTag + "', not a tag" );
380         }
381 
382         StringTokenizer tokens = new StringTokenizer( beginTag, "<> \t\n\r\f" );
383         if ( !tokens.hasMoreTokens() )
384         {
385             throw new IllegalArgumentException( "'" + beginTag + "', invalid tag" );
386         }
387 
388         return "</" + tokens.nextToken() + ">";
389     }
390 
391     /**
392      * Returns the current italicBeginTag.
393      *
394      * @return the current italicBeginTag. Defaults to {@code <emphasis>}.
395      */
396     public String getItalicElement()
397     {
398         return italicBeginTag;
399     }
400 
401     /**
402      * Sets the current boldBeginTag and constructs the corresponding end tag from it.
403      *
404      * @param tag the tag to set. If tag is null, the empty string is used.
405      */
406     public void setBoldElement( String tag )
407     {
408         if ( tag == null )
409         {
410             tag = "";
411         }
412         this.boldBeginTag = tag;
413         boldEndTag = makeEndTag( boldBeginTag );
414     }
415 
416     /**
417      * Returns the current boldBeginTag.
418      *
419      * @return the current boldBeginTag. Defaults to {@code <emphasis role=\"bold\">}.
420      */
421     public String getBoldElement()
422     {
423         return boldBeginTag;
424     }
425 
426     /**
427      * Sets the current monospacedBeginTag and constructs the corresponding end tag from it.
428      *
429      * @param tag the tag to set. If tag is null, the empty string is used.
430      */
431     public void setMonospacedElement( String tag )
432     {
433         if ( tag == null )
434         {
435             tag = "";
436         }
437         this.monospacedBeginTag = tag;
438         monospacedEndTag = makeEndTag( monospacedBeginTag );
439     }
440 
441     /**
442      * Returns the current monospacedBeginTag.
443      *
444      * @return the current monospacedBeginTag. Defaults to {@code <literal>}.
445      */
446     public String getMonospacedElement()
447     {
448         return monospacedBeginTag;
449     }
450 
451     /**
452      * Sets the current horizontalRuleElement.
453      *
454      * @param element the element to set.
455      */
456     public void setHorizontalRuleElement( String element )
457     {
458         this.horizontalRuleElement = element;
459     }
460 
461     /**
462      * Returns the current horizontalRuleElement.
463      *
464      * @return the current horizontalRuleElement. Defaults to "<!-- HR -->".
465      */
466     public String getHorizontalRuleElement()
467     {
468         return horizontalRuleElement;
469     }
470 
471     /**
472      * Sets the current pageBreakElement.
473      *
474      * @param element the element to set.
475      */
476     public void setPageBreakElement( String element )
477     {
478         this.pageBreakElement = element;
479     }
480 
481     /**
482      * Returns the current pageBreakElement.
483      *
484      * @return the current pageBreakElement. Defaults to "<!-- PB -->".
485      */
486     public String getPageBreakElement()
487     {
488         return pageBreakElement;
489     }
490 
491     /**
492      * Sets the current lineBreakElement.
493      *
494      * @param element the element to set.
495      */
496     public void setLineBreakElement( String element )
497     {
498         this.lineBreakElement = element;
499     }
500 
501     /**
502      * Returns the current lineBreakElement.
503      *
504      * @return the current lineBreakElement. Defaults to "<!-- LB -->".
505      */
506     public String getLineBreakElement()
507     {
508         return lineBreakElement;
509     }
510 
511     /**
512      * Reset all variables.
513      *
514      * @deprecated since 1.1.2, use {@link #init()} instead of.
515      */
516     protected void resetState()
517     {
518        init();
519     }
520 
521     /**
522      * {@inheritDoc}
523      */
524     protected void init()
525     {
526         hasTitle = false;
527         authorDateFlag = false;
528         verbatimFlag = false;
529         externalLinkFlag = false;
530         graphicsFileName = null;
531         tableHasCaption = false;
532         savedOut = null;
533         tableRows = null;
534         tableHasGrid = false;
535     }
536 
537     // ----------------------------------------------------------------------
538     //
539     // ----------------------------------------------------------------------
540 
541     /**
542      * {@inheritDoc}
543      *
544      * @see SimplifiedDocbookMarkup#DEFAULT_XML_PUBLIC_ID
545      * @see SimplifiedDocbookMarkup#DEFAULT_XML_SYSTEM_ID
546      * @see SimplifiedDocbookMarkup#ARTICLE_TAG
547      */
548     public void head()
549     {
550         init();
551 
552         MutableAttributeSet att = writeXmlHeader( "article" );
553 
554         writeStartTag( SimplifiedDocbookMarkup.ARTICLE_TAG, att );
555     }
556 
557     /**
558      * writeXmlHeader.
559      *
560      * @param root not null.
561      * @return an attribute set.
562      * @see SimplifiedDocbookMarkup#DEFAULT_XML_PUBLIC_ID
563      * @see SimplifiedDocbookMarkup#DEFAULT_XML_SYSTEM_ID
564      * @see SimplifiedDocbookMarkup#ARTICLE_TAG
565      * @since 1.1
566      */
567     protected MutableAttributeSet writeXmlHeader( String root )
568     {
569         markup( "<?xml version=\"1.0\"" );
570         if ( encoding != null )
571         {
572             markup( " encoding=\"" + encoding + "\"" );
573         }
574         markup( "?>" );
575 
576         if ( styleSheet != null )
577         {
578             markup( "<?xml-stylesheet type=\"text/css\" href=\"" + styleSheet + "\" ?>" );
579         }
580 
581         String pubId;
582         markup( "<!DOCTYPE " + root + " PUBLIC" );
583 
584         if ( publicId == null )
585         {
586             pubId = SimplifiedDocbookMarkup.DEFAULT_XML_PUBLIC_ID;
587         }
588         else
589         {
590             pubId = publicId;
591         }
592         markup( " \"" + pubId + "\"" );
593         String sysId = systemId;
594         if ( sysId == null )
595         {
596                 sysId = SimplifiedDocbookMarkup.DEFAULT_XML_SYSTEM_ID;
597         }
598         markup( " \"" + sysId + "\">" );
599 
600         MutableAttributeSet att = new SimpleAttributeSet();
601         if ( lang != null )
602         {
603             att.addAttribute( LANG_ATTRIBUTE, lang );
604         }
605         return att;
606     }
607 
608     /**
609      * {@inheritDoc}
610      *
611      * @see SimplifiedDocbookMarkup#ARTICLEINFO_TAG
612      */
613     public void head_()
614     {
615         if ( hasTitle )
616         {
617             writeEndTag( SimplifiedDocbookMarkup.ARTICLEINFO_TAG );
618             hasTitle = false;
619         }
620     }
621 
622     /**
623      * {@inheritDoc}
624      *
625      * @see SimplifiedDocbookMarkup#ARTICLEINFO_TAG
626      * @see SimplifiedDocbookMarkup#TITLE_TAG
627      */
628     public void title()
629     {
630         writeStartTag( SimplifiedDocbookMarkup.ARTICLEINFO_TAG );
631         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
632         hasTitle = true;
633     }
634 
635     /**
636      * {@inheritDoc}
637      *
638      * @see SimplifiedDocbookMarkup#TITLE_TAG
639      */
640     public void title_()
641     {
642         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
643     }
644 
645     /**
646      * {@inheritDoc}
647      *
648      * @see SimplifiedDocbookMarkup#CORPAUTHOR_TAG
649      */
650     public void author()
651     {
652         authorDateFlag = true;
653         writeStartTag( SimplifiedDocbookMarkup.CORPAUTHOR_TAG );
654     }
655 
656     /**
657      * {@inheritDoc}
658      *
659      * @see SimplifiedDocbookMarkup#CORPAUTHOR_TAG
660      */
661     public void author_()
662     {
663         writeEndTag( SimplifiedDocbookMarkup.CORPAUTHOR_TAG );
664         authorDateFlag = false;
665     }
666 
667     /**
668      * {@inheritDoc}
669      *
670      * @see SimplifiedDocbookMarkup#DATE_TAG
671      */
672     public void date()
673     {
674         authorDateFlag = true;
675         writeStartTag( SimplifiedDocbookMarkup.DATE_TAG );
676     }
677 
678     /**
679      * {@inheritDoc}
680      *
681      * @see SimplifiedDocbookMarkup#DATE_TAG
682      */
683     public void date_()
684     {
685         writeEndTag( SimplifiedDocbookMarkup.DATE_TAG );
686         authorDateFlag = false;
687     }
688 
689     /**
690      * {@inheritDoc}
691      *
692      * @see SimplifiedDocbookMarkup#ARTICLE_TAG
693      */
694     public void body_()
695     {
696         writeEndTag( SimplifiedDocbookMarkup.ARTICLE_TAG );
697         out.flush();
698         init();
699     }
700 
701     /**
702      * {@inheritDoc}
703      *
704      * @see SimplifiedDocbookMarkup#SIDEBAR_TAG
705      */
706     public void sidebar()
707     {
708         writeStartTag( SimplifiedDocbookMarkup.SIDEBAR_TAG );
709     }
710 
711     /**
712      * {@inheritDoc}
713      *
714      * @see SimplifiedDocbookMarkup#SIDEBAR_TAG
715      */
716     public void sidebar_()
717     {
718         writeEndTag( SimplifiedDocbookMarkup.SIDEBAR_TAG );
719     }
720 
721     /**
722      * {@inheritDoc}
723      *
724      * @see SimplifiedDocbookMarkup#SECTION_TAG
725      */
726     public void section1()
727     {
728         writeStartTag( SimplifiedDocbookMarkup.SECTION_TAG );
729     }
730 
731     /**
732      * {@inheritDoc}
733      *
734      * @see SimplifiedDocbookMarkup#SECTION_TAG
735      */
736     public void section1_()
737     {
738         writeEndTag( SimplifiedDocbookMarkup.SECTION_TAG );
739     }
740 
741     /**
742      * {@inheritDoc}
743      *
744      * @see SimplifiedDocbookMarkup#SECTION_TAG
745      */
746     public void section2()
747     {
748         writeStartTag( SimplifiedDocbookMarkup.SECTION_TAG );
749     }
750 
751     /**
752      * {@inheritDoc}
753      *
754      * @see SimplifiedDocbookMarkup#SECTION_TAG
755      */
756     public void section2_()
757     {
758         writeEndTag( SimplifiedDocbookMarkup.SECTION_TAG );
759     }
760 
761     /**
762      * {@inheritDoc}
763      *
764      * @see SimplifiedDocbookMarkup#SECTION_TAG
765      */
766     public void section3()
767     {
768         writeStartTag( SimplifiedDocbookMarkup.SECTION_TAG );
769     }
770 
771     /**
772      * {@inheritDoc}
773      *
774      * @see SimplifiedDocbookMarkup#SECTION_TAG
775      */
776     public void section3_()
777     {
778         writeEndTag( SimplifiedDocbookMarkup.SECTION_TAG );
779     }
780 
781     /**
782      * {@inheritDoc}
783      *
784      * @see SimplifiedDocbookMarkup#SECTION_TAG
785      */
786     public void section4()
787     {
788         writeStartTag( SimplifiedDocbookMarkup.SECTION_TAG );
789     }
790 
791     /**
792      * {@inheritDoc}
793      *
794      * @see SimplifiedDocbookMarkup#SECTION_TAG
795      */
796     public void section4_()
797     {
798         writeEndTag( SimplifiedDocbookMarkup.SECTION_TAG );
799     }
800 
801     /**
802      * {@inheritDoc}
803      *
804      * @see SimplifiedDocbookMarkup#SECTION_TAG
805      */
806     public void section5()
807     {
808         writeStartTag( SimplifiedDocbookMarkup.SECTION_TAG );
809     }
810 
811     /**
812      * {@inheritDoc}
813      *
814      * @see SimplifiedDocbookMarkup#SECTION_TAG
815      */
816     public void section5_()
817     {
818         writeEndTag( SimplifiedDocbookMarkup.SECTION_TAG );
819     }
820 
821     /**
822      * {@inheritDoc}
823      *
824      * @see SimplifiedDocbookMarkup#TITLE_TAG
825      */
826     public void sectionTitle()
827     {
828         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
829     }
830 
831     /**
832      * {@inheritDoc}
833      *
834      * @see SimplifiedDocbookMarkup#TITLE_TAG
835      */
836     public void sectionTitle_()
837     {
838         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
839     }
840 
841     /**
842      * {@inheritDoc}
843      *
844      * @see SimplifiedDocbookMarkup#TITLE_TAG
845      */
846     public void sectionTitle1()
847     {
848         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
849     }
850 
851     /**
852      * {@inheritDoc}
853      *
854      * @see SimplifiedDocbookMarkup#TITLE_TAG
855      */
856     public void sectionTitle1_()
857     {
858         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
859     }
860 
861     /**
862      * {@inheritDoc}
863      *
864      * @see SimplifiedDocbookMarkup#TITLE_TAG
865      */
866     public void sectionTitle2()
867     {
868         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
869     }
870 
871     /**
872      * {@inheritDoc}
873      *
874      * @see SimplifiedDocbookMarkup#TITLE_TAG
875      */
876     public void sectionTitle2_()
877     {
878         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
879     }
880 
881     /**
882      * {@inheritDoc}
883      *
884      * @see SimplifiedDocbookMarkup#TITLE_TAG
885      */
886     public void sectionTitle3()
887     {
888         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
889     }
890 
891     /**
892      * {@inheritDoc}
893      *
894      * @see SimplifiedDocbookMarkup#TITLE_TAG
895      */
896     public void sectionTitle3_()
897     {
898         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
899     }
900 
901     /**
902      * {@inheritDoc}
903      *
904      * @see SimplifiedDocbookMarkup#TITLE_TAG
905      */
906     public void sectionTitle4()
907     {
908         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
909     }
910 
911     /**
912      * {@inheritDoc}
913      *
914      * @see SimplifiedDocbookMarkup#TITLE_TAG
915      */
916     public void sectionTitle4_()
917     {
918         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
919     }
920 
921     /**
922      * {@inheritDoc}
923      *
924      * @see SimplifiedDocbookMarkup#TITLE_TAG
925      */
926     public void sectionTitle5()
927     {
928         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
929     }
930 
931     /**
932      * {@inheritDoc}
933      *
934      * @see SimplifiedDocbookMarkup#TITLE_TAG
935      */
936     public void sectionTitle5_()
937     {
938         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
939     }
940 
941     /**
942      * {@inheritDoc}
943      *
944      * @see SimplifiedDocbookMarkup#SECTIONINFO_TAG
945      */
946     public void header()
947     {
948         writeStartTag( SimplifiedDocbookMarkup.SECTIONINFO_TAG );
949     }
950 
951     /**
952      * {@inheritDoc}
953      *
954      * @see SimplifiedDocbookMarkup#SECTIONINFO_TAG
955      */
956     public void header_()
957     {
958         writeEndTag( SimplifiedDocbookMarkup.SECTIONINFO_TAG );
959     }
960 
961     /**
962      * {@inheritDoc}
963      *
964      * @see SimplifiedDocbookMarkup#ITEMIZEDLIST_TAG
965      */
966     public void list()
967     {
968         paragraph_();
969         writeStartTag( SimplifiedDocbookMarkup.ITEMIZEDLIST_TAG );
970     }
971 
972     /**
973      * {@inheritDoc}
974      *
975      * @see SimplifiedDocbookMarkup#ITEMIZEDLIST_TAG
976      */
977     public void list_()
978     {
979         writeEndTag( SimplifiedDocbookMarkup.ITEMIZEDLIST_TAG );
980     }
981 
982     /**
983      * {@inheritDoc}
984      *
985      * @see SimplifiedDocbookMarkup#LISTITEM_TAG
986      */
987     public void listItem()
988     {
989         writeStartTag( SimplifiedDocbookMarkup.LISTITEM_TAG );
990         paragraph();
991     }
992 
993     /**
994      * {@inheritDoc}
995      *
996      * @see SimplifiedDocbookMarkup#LISTITEM_TAG
997      */
998     public void listItem_()
999     {
1000         paragraph_();
1001         writeEndTag( SimplifiedDocbookMarkup.LISTITEM_TAG );
1002     }
1003 
1004     /**
1005      * {@inheritDoc}
1006      * @see SimplifiedDocbookMarkup#ORDEREDLIST_TAG
1007      * @see SimplifiedDocbookMarkup#NUMERATION_ATTRIBUTE
1008      */
1009     public void numberedList( int numbering )
1010     {
1011         String numeration = DocbookUtils.docbookListNumbering( numbering );
1012 
1013         paragraph_();
1014 
1015         MutableAttributeSet att = new SimpleAttributeSet();
1016         att.addAttribute( SimplifiedDocbookMarkup.NUMERATION_ATTRIBUTE, numeration );
1017 
1018         writeStartTag( SimplifiedDocbookMarkup.ORDEREDLIST_TAG, att );
1019     }
1020 
1021     /**
1022      * {@inheritDoc}
1023      *
1024      * @see SimplifiedDocbookMarkup#ORDEREDLIST_TAG
1025      */
1026     public void numberedList_()
1027     {
1028         writeEndTag( SimplifiedDocbookMarkup.ORDEREDLIST_TAG );
1029     }
1030 
1031     /**
1032      * {@inheritDoc}
1033      *
1034      * @see SimplifiedDocbookMarkup#LISTITEM_TAG
1035      */
1036     public void numberedListItem()
1037     {
1038         writeStartTag( SimplifiedDocbookMarkup.LISTITEM_TAG );
1039         paragraph();
1040     }
1041 
1042     /**
1043      * {@inheritDoc}
1044      *
1045      * @see SimplifiedDocbookMarkup#LISTITEM_TAG
1046      */
1047     public void numberedListItem_()
1048     {
1049         paragraph_();
1050         writeEndTag( SimplifiedDocbookMarkup.LISTITEM_TAG );
1051     }
1052 
1053     /**
1054      * {@inheritDoc}
1055      *
1056      * @see SimplifiedDocbookMarkup#VARIABLELIST_TAG
1057      */
1058     public void definitionList()
1059     {
1060         paragraph_();
1061         writeStartTag( SimplifiedDocbookMarkup.VARIABLELIST_TAG );
1062     }
1063 
1064     /**
1065      * {@inheritDoc}
1066      *
1067      * @see SimplifiedDocbookMarkup#VARIABLELIST_TAG
1068      */
1069     public void definitionList_()
1070     {
1071         writeEndTag( SimplifiedDocbookMarkup.VARIABLELIST_TAG );
1072     }
1073 
1074     /**
1075      * {@inheritDoc}
1076      *
1077      * @see SimplifiedDocbookMarkup#VARLISTENTRY_TAG
1078      */
1079     public void definitionListItem()
1080     {
1081         writeStartTag( SimplifiedDocbookMarkup.VARLISTENTRY_TAG );
1082     }
1083 
1084     /**
1085      * {@inheritDoc}
1086      *
1087      * @see SimplifiedDocbookMarkup#VARLISTENTRY_TAG
1088      */
1089     public void definitionListItem_()
1090     {
1091         writeEndTag( SimplifiedDocbookMarkup.VARLISTENTRY_TAG );
1092     }
1093 
1094     /**
1095      * {@inheritDoc}
1096      *
1097      * @see SimplifiedDocbookMarkup#TERM_TAG
1098      */
1099     public void definedTerm()
1100     {
1101         writeStartTag( SimplifiedDocbookMarkup.TERM_TAG );
1102     }
1103 
1104     /**
1105      * {@inheritDoc}
1106      *
1107      * @see SimplifiedDocbookMarkup#TERM_TAG
1108      */
1109     public void definedTerm_()
1110     {
1111         writeEndTag( SimplifiedDocbookMarkup.TERM_TAG );
1112     }
1113 
1114     /**
1115      * {@inheritDoc}
1116      *
1117      * @see SimplifiedDocbookMarkup#LISTITEM_TAG
1118      */
1119     public void definition()
1120     {
1121         writeStartTag( SimplifiedDocbookMarkup.LISTITEM_TAG );
1122         paragraph();
1123     }
1124 
1125     /**
1126      * {@inheritDoc}
1127      *
1128      * @see SimplifiedDocbookMarkup#LISTITEM_TAG
1129      */
1130     public void definition_()
1131     {
1132         paragraph_();
1133         writeEndTag( SimplifiedDocbookMarkup.LISTITEM_TAG );
1134     }
1135 
1136     /**
1137      * {@inheritDoc}
1138      *
1139      * @see SimplifiedDocbookMarkup#PARA_TAG
1140      */
1141     public void paragraph()
1142     {
1143         if ( !paragraph )
1144         {
1145             writeStartTag( SimplifiedDocbookMarkup.PARA_TAG );
1146             paragraph = true;
1147         }
1148     }
1149 
1150     /**
1151      * {@inheritDoc}
1152      *
1153      * @see SimplifiedDocbookMarkup#PARA_TAG
1154      */
1155     public void paragraph_()
1156     {
1157         if ( paragraph )
1158         {
1159             writeEndTag( SimplifiedDocbookMarkup.PARA_TAG );
1160             paragraph = false;
1161         }
1162     }
1163 
1164     /**
1165      * {@inheritDoc}
1166      * @see SimplifiedDocbookMarkup#PROGRAMLISTING_TAG
1167      */
1168     public void verbatim( boolean boxed )
1169     {
1170         verbatimFlag = true;
1171         paragraph_();
1172         writeStartTag( SimplifiedDocbookMarkup.PROGRAMLISTING_TAG );
1173     }
1174 
1175     /**
1176      * {@inheritDoc}
1177      *
1178      * @see SimplifiedDocbookMarkup#PROGRAMLISTING_TAG
1179      */
1180     public void verbatim_()
1181     {
1182         writeEndTag( SimplifiedDocbookMarkup.PROGRAMLISTING_TAG );
1183         verbatimFlag = false;
1184     }
1185 
1186     /**
1187      * {@inheritDoc}
1188      */
1189     public void horizontalRule()
1190     {
1191         markup( horizontalRuleElement );
1192     }
1193 
1194     /**
1195      * {@inheritDoc}
1196      */
1197     public void pageBreak()
1198     {
1199         markup( pageBreakElement );
1200     }
1201 
1202     /**
1203      * {@inheritDoc}
1204      */
1205     public void figure()
1206     {
1207         writeStartTag( SimplifiedDocbookMarkup.MEDIAOBJECT_TAG );
1208     }
1209 
1210     /**
1211      * {@inheritDoc}
1212      */
1213     public void figure_()
1214     {
1215         writeEndTag( SimplifiedDocbookMarkup.MEDIAOBJECT_TAG );
1216     }
1217 
1218     /**
1219      * <p>graphicElement</p>
1220      *
1221      * @see SimplifiedDocbookMarkup#MEDIAOBJECT_TAG
1222      * @see SimplifiedDocbookMarkup#IMAGEOBJECT_TAG
1223      * @see SimplifiedDocbookMarkup#IMAGEDATA_TAG
1224      * @see SimplifiedDocbookMarkup#FORMAT_ATTRIBUTE
1225      * @see SimplifiedDocbookMarkup#FILEREF_ATTRIBUTE
1226      * @deprecated do not use!
1227      */
1228     protected void graphicElement()
1229     {
1230         if ( graphicsFileName != null )
1231         {
1232             String format = FileUtils.extension( graphicsFileName ).toUpperCase( Locale.ENGLISH );
1233             if ( format.length() == 0 )
1234             {
1235                 format = "JPEG";
1236             }
1237 
1238             writeStartTag( SimplifiedDocbookMarkup.MEDIAOBJECT_TAG );
1239             writeStartTag( SimplifiedDocbookMarkup.IMAGEOBJECT_TAG );
1240 
1241             MutableAttributeSet att = new SimpleAttributeSet();
1242             att.addAttribute( SimplifiedDocbookMarkup.FORMAT_ATTRIBUTE, escapeHTML( format, true ) );
1243             att.addAttribute( SimplifiedDocbookMarkup.FILEREF_ATTRIBUTE, escapeHTML( graphicsFileName, true ) );
1244 
1245             writeSimpleTag( SimplifiedDocbookMarkup.IMAGEDATA_TAG, att );
1246 
1247             writeEndTag( SimplifiedDocbookMarkup.IMAGEOBJECT_TAG );
1248             writeEndTag( SimplifiedDocbookMarkup.MEDIAOBJECT_TAG );
1249             graphicsFileName = null;
1250         }
1251     }
1252 
1253     /** {@inheritDoc} */
1254     public void figureGraphics( String name )
1255     {
1256         String format = FileUtils.extension( name ).toUpperCase( Locale.ENGLISH );
1257 
1258         writeStartTag( SimplifiedDocbookMarkup.IMAGEOBJECT_TAG );
1259 
1260         MutableAttributeSet att = new SimpleAttributeSet();
1261         att.addAttribute( SimplifiedDocbookMarkup.FORMAT_ATTRIBUTE, escapeHTML( format, true ) );
1262         att.addAttribute( SimplifiedDocbookMarkup.FILEREF_ATTRIBUTE, escapeHTML( name, true ) );
1263 
1264         writeSimpleTag( SimplifiedDocbookMarkup.IMAGEDATA_TAG, att );
1265 
1266         writeEndTag( SimplifiedDocbookMarkup.IMAGEOBJECT_TAG );
1267     }
1268 
1269     /**
1270      * {@inheritDoc}
1271      *
1272      * @see SimplifiedDocbookMarkup#FIGURE_TAG
1273      * @see SimplifiedDocbookMarkup#TITLE_TAG
1274      */
1275     public void figureCaption()
1276     {
1277         writeStartTag( SimplifiedDocbookMarkup.CAPTION_TAG );
1278         writeStartTag( SimplifiedDocbookMarkup.PARA_TAG );
1279     }
1280 
1281     /**
1282      * {@inheritDoc}
1283      *
1284      * @see SimplifiedDocbookMarkup#FIGURE_TAG
1285      * @see SimplifiedDocbookMarkup#TITLE_TAG
1286      */
1287     public void figureCaption_()
1288     {
1289         writeEndTag( SimplifiedDocbookMarkup.PARA_TAG );
1290         writeEndTag( SimplifiedDocbookMarkup.CAPTION_TAG );
1291     }
1292 
1293     /**
1294      * {@inheritDoc}
1295      */
1296     public void table()
1297     {
1298         tableHasCaption = false;
1299     }
1300 
1301     /**
1302      * {@inheritDoc}
1303      *
1304      * @see SimplifiedDocbookMarkup#INFORMALTABLE_TAG
1305      * @see SimplifiedDocbookMarkup#FRAME_ATTRIBUTE
1306      * @see SimplifiedDocbookMarkup#ROWSEP_ATTRIBUTE
1307      * @see SimplifiedDocbookMarkup#COLSEP_ATTRIBUTE
1308      * @see SimplifiedDocbookMarkup#TABLE_TAG
1309      */
1310     public void table_()
1311     {
1312         if ( tableHasCaption )
1313         {
1314             tableHasCaption = false;
1315             // Formal table+title already written to original destination ---
1316 
1317             out.write( tableRows  );
1318             writeEndTag( TABLE_TAG );
1319         }
1320         else
1321         {
1322             String frame = "none";
1323             String sep = "0";
1324             if ( tableHasGrid )
1325             {
1326                 frame = "all";
1327                 sep = "1";
1328             }
1329 
1330             MutableAttributeSet att = new SimpleAttributeSet();
1331             att.addAttribute( SimplifiedDocbookMarkup.FRAME_ATTRIBUTE, frame );
1332             att.addAttribute( SimplifiedDocbookMarkup.ROWSEP_ATTRIBUTE, sep );
1333             att.addAttribute( SimplifiedDocbookMarkup.COLSEP_ATTRIBUTE, sep );
1334 
1335             writeStartTag( SimplifiedDocbookMarkup.INFORMALTABLE_TAG, att );
1336 
1337             out.write( tableRows  );
1338 
1339             writeEndTag( SimplifiedDocbookMarkup.INFORMALTABLE_TAG );
1340         }
1341 
1342         tableRows = null;
1343         tableHasGrid = false;
1344     }
1345 
1346     /**
1347      * {@inheritDoc}
1348      * @see SimplifiedDocbookMarkup#TGROUP_TAG
1349      * @see SimplifiedDocbookMarkup#COLS_ATTRIBUTE
1350      * @see SimplifiedDocbookMarkup#COLSPEC_TAG
1351      */
1352     public void tableRows( int[] justification, boolean grid )
1353     {
1354         tableHasGrid = grid;
1355 
1356         // Divert output to a string ---
1357         out.flush();
1358         savedOut = out;
1359         tableRowsWriter = new StringWriter();
1360         out = new PrintWriter( tableRowsWriter );
1361 
1362         MutableAttributeSet att = new SimpleAttributeSet();
1363         att.addAttribute( SimplifiedDocbookMarkup.COLS_ATTRIBUTE, String.valueOf( justification.length ) );
1364 
1365         writeStartTag( SimplifiedDocbookMarkup.TGROUP_TAG, att );
1366 
1367         for ( int i1 : justification )
1368         {
1369             String justif;
1370             switch ( i1 )
1371             {
1372                 case Sink.JUSTIFY_LEFT:
1373                     justif = "left";
1374                     break;
1375                 case Sink.JUSTIFY_RIGHT:
1376                     justif = "right";
1377                     break;
1378                 case Sink.JUSTIFY_CENTER:
1379                 default:
1380                     justif = "center";
1381                     break;
1382             }
1383 
1384             att = new SimpleAttributeSet();
1385             att.addAttribute( "align", justif );
1386 
1387             writeSimpleTag( SimplifiedDocbookMarkup.COLSPEC_TAG, att );
1388         }
1389 
1390         writeStartTag( SimplifiedDocbookMarkup.TBODY_TAG );
1391     }
1392 
1393     /**
1394      * {@inheritDoc}
1395      *
1396      * @see SimplifiedDocbookMarkup#TGROUP_TAG
1397      * @see SimplifiedDocbookMarkup#TBODY_TAG
1398      */
1399     public void tableRows_()
1400     {
1401         writeEndTag( SimplifiedDocbookMarkup.TBODY_TAG );
1402         writeEndTag( SimplifiedDocbookMarkup.TGROUP_TAG );
1403 
1404         // Remember diverted output and restore original destination ---
1405         out.flush();
1406         if ( tableRowsWriter == null )
1407         {
1408             throw new IllegalArgumentException( "tableRows( int[] justification, boolean grid )"
1409                                                 + " was not called before." );
1410         }
1411 
1412         tableRows = tableRowsWriter.toString();
1413         tableRowsWriter = null;
1414         out = savedOut;
1415     }
1416 
1417     /**
1418      * {@inheritDoc}
1419      *
1420      * @see SimplifiedDocbookMarkup#ROW_TAG
1421      */
1422     public void tableRow()
1423     {
1424         writeStartTag( SimplifiedDocbookMarkup.ROW_TAG );
1425     }
1426 
1427     /**
1428      * {@inheritDoc}
1429      *
1430      * @see SimplifiedDocbookMarkup#ROW_TAG
1431      */
1432     public void tableRow_()
1433     {
1434         writeEndTag( SimplifiedDocbookMarkup.ROW_TAG );
1435     }
1436 
1437     /**
1438      * {@inheritDoc}
1439      *
1440      * @see SimplifiedDocbookMarkup#ENTRY_TAG
1441      */
1442     public void tableCell()
1443     {
1444         writeStartTag( SimplifiedDocbookMarkup.ENTRY_TAG );
1445     }
1446 
1447     /**
1448      * {@inheritDoc}
1449      *
1450      * @see SimplifiedDocbookMarkup#ENTRY_TAG
1451      */
1452     public void tableCell_()
1453     {
1454         writeEndTag( SimplifiedDocbookMarkup.ENTRY_TAG );
1455     }
1456 
1457     /**
1458      * {@inheritDoc}
1459      *
1460      * @see SimplifiedDocbookMarkup#ENTRY_TAG
1461      */
1462     public void tableHeaderCell()
1463     {
1464         writeStartTag( SimplifiedDocbookMarkup.ENTRY_TAG );
1465     }
1466 
1467     /**
1468      * {@inheritDoc}
1469      *
1470      * @see SimplifiedDocbookMarkup#ENTRY_TAG
1471      */
1472     public void tableHeaderCell_()
1473     {
1474         writeEndTag( SimplifiedDocbookMarkup.ENTRY_TAG );
1475     }
1476 
1477     /**
1478      * {@inheritDoc}
1479      *
1480      * @see SimplifiedDocbookMarkup#TABLE_TAG
1481      * @see SimplifiedDocbookMarkup#FRAME_ATTRIBUTE
1482      * @see SimplifiedDocbookMarkup#ROWSEP_ATTRIBUTE
1483      * @see SimplifiedDocbookMarkup#COLSEP_ATTRIBUTE
1484      * @see SimplifiedDocbookMarkup#TITLE_TAG
1485      */
1486     public void tableCaption()
1487     {
1488         tableHasCaption = true;
1489 
1490         String frame;
1491         int sep;
1492         if ( tableHasGrid )
1493         {
1494             frame = "all";
1495             sep = 1;
1496         }
1497         else
1498         {
1499             frame = "none";
1500             sep = 0;
1501         }
1502 
1503         MutableAttributeSet att = new SimpleAttributeSet();
1504         att.addAttribute( SimplifiedDocbookMarkup.FRAME_ATTRIBUTE, frame );
1505         att.addAttribute( SimplifiedDocbookMarkup.ROWSEP_ATTRIBUTE, String.valueOf( sep ) );
1506         att.addAttribute( SimplifiedDocbookMarkup.COLSEP_ATTRIBUTE, String.valueOf( sep ) );
1507 
1508         writeStartTag( TABLE_TAG, att );
1509 
1510         writeStartTag( SimplifiedDocbookMarkup.TITLE_TAG );
1511     }
1512 
1513     /**
1514      * {@inheritDoc}
1515      *
1516      * @see SimplifiedDocbookMarkup#TITLE_TAG
1517      */
1518     public void tableCaption_()
1519     {
1520         writeEndTag( SimplifiedDocbookMarkup.TITLE_TAG );
1521     }
1522 
1523     /**
1524      * {@inheritDoc}
1525      * @see SimplifiedDocbookMarkup#ANCHOR_TAG
1526      */
1527     public void anchor( String name )
1528     {
1529         if ( name == null )
1530         {
1531             throw new NullPointerException( "Anchor name cannot be null!" );
1532         }
1533 
1534         if ( authorDateFlag )
1535         {
1536             return;
1537         }
1538 
1539         String id = name;
1540 
1541         if ( !DoxiaUtils.isValidId( id ) )
1542         {
1543             id = DoxiaUtils.encodeId( name, true );
1544 
1545             String msg = "Modified invalid anchor name: '" + name + "' to '" + id + "'";
1546             logMessage( "modifiedLink", msg );
1547         }
1548 
1549         MutableAttributeSet att = new SimpleAttributeSet();
1550         att.addAttribute( ID_ATTRIBUTE, id );
1551 
1552         writeSimpleTag( SimplifiedDocbookMarkup.ANCHOR_TAG, att );
1553     }
1554 
1555     /**
1556      * {@inheritDoc}
1557      *
1558      * @see SimplifiedDocbookMarkup#ANCHOR_TAG
1559      */
1560     public void anchor_()
1561     {
1562         comment( " anchor_end " );
1563     }
1564 
1565     /**
1566      * {@inheritDoc}
1567      * @see SimplifiedDocbookMarkup#ULINK_TAG
1568      * @see SimplifiedDocbookMarkup#URL_ATTRIBUTE
1569      * @see SimplifiedDocbookMarkup#LINK_TAG
1570      * @see SimplifiedDocbookMarkup#LINKEND_ATTRIBUTE
1571      */
1572     public void link( String name )
1573     {
1574         if ( name == null )
1575         {
1576             throw new NullPointerException( "Link name cannot be null!" );
1577         }
1578 
1579         if ( DoxiaUtils.isInternalLink( name ) )
1580         {
1581             String linkend = name.substring( 1 );
1582             MutableAttributeSet att = new SimpleAttributeSet();
1583             att.addAttribute( SimplifiedDocbookMarkup.LINKEND_ATTRIBUTE, escapeHTML( linkend ) );
1584 
1585             writeStartTag( SimplifiedDocbookMarkup.LINK_TAG, att );
1586         }
1587         else
1588         {
1589             externalLinkFlag = true;
1590             MutableAttributeSet att = new SimpleAttributeSet();
1591             att.addAttribute( SimplifiedDocbookMarkup.URL_ATTRIBUTE, escapeHTML( name, true ) );
1592 
1593             writeStartTag( SimplifiedDocbookMarkup.ULINK_TAG, att );
1594         }
1595     }
1596 
1597     /**
1598      * {@inheritDoc}
1599      *
1600      * @see SimplifiedDocbookMarkup#ULINK_TAG
1601      * @see SimplifiedDocbookMarkup#LINK_TAG
1602      */
1603     public void link_()
1604     {
1605         if ( externalLinkFlag )
1606         {
1607             writeEndTag( SimplifiedDocbookMarkup.ULINK_TAG );
1608             externalLinkFlag = false;
1609         }
1610         else
1611         {
1612             writeEndTag( SimplifiedDocbookMarkup.LINK_TAG );
1613         }
1614     }
1615 
1616     /**
1617      * {@inheritDoc}
1618      */
1619     public void inline()
1620     {
1621         inline( null );
1622     }
1623 
1624     /** {@inheritDoc} */
1625     public void inline( SinkEventAttributes attributes )
1626     {
1627         List<String> tags = new ArrayList<>();
1628 
1629         if ( attributes != null )
1630         {
1631 
1632             if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
1633             {
1634                 markup( italicBeginTag );
1635                 tags.add( 0, italicEndTag );
1636             }
1637 
1638             if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
1639             {
1640                 write( boldBeginTag );
1641                 tags.add( 0, boldEndTag );
1642             }
1643 
1644             if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
1645             {
1646                 if ( !authorDateFlag )
1647                 {
1648                     write( monospacedBeginTag );
1649                     tags.add( 0, monospacedEndTag );
1650                 }
1651             }
1652 
1653         }
1654 
1655         inlineStack.push( tags );
1656     }
1657 
1658     /**
1659      * {@inheritDoc}
1660      */
1661     public void inline_()
1662     {
1663         for ( String tag: inlineStack.pop() )
1664         {
1665             markup( tag );
1666         }
1667     }
1668 
1669     /**
1670      * {@inheritDoc}
1671      */
1672     public void italic()
1673     {
1674         inline( SinkEventAttributeSet.Semantics.ITALIC );
1675     }
1676 
1677     /**
1678      * {@inheritDoc}
1679      */
1680     public void italic_()
1681     {
1682         inline_();
1683     }
1684 
1685     /**
1686      * {@inheritDoc}
1687      */
1688     public void bold()
1689     {
1690         inline( SinkEventAttributeSet.Semantics.BOLD );
1691     }
1692 
1693     /**
1694      * {@inheritDoc}
1695      */
1696     public void bold_()
1697     {
1698         inline_();
1699     }
1700 
1701     /**
1702      * {@inheritDoc}
1703      */
1704     public void monospaced()
1705     {
1706         inline( SinkEventAttributeSet.Semantics.CODE );
1707     }
1708 
1709     /**
1710      * {@inheritDoc}
1711      */
1712     public void monospaced_()
1713     {
1714         inline_();
1715     }
1716 
1717     /**
1718      * {@inheritDoc}
1719      */
1720     public void lineBreak()
1721     {
1722         markup( lineBreakElement );
1723     }
1724 
1725     /**
1726      * {@inheritDoc}
1727      */
1728     public void nonBreakingSpace()
1729     {
1730         markup( "&#x00A0;" );
1731         //markup( "&nbsp;" );
1732     }
1733 
1734     /** {@inheritDoc} */
1735     public void text( String text )
1736     {
1737         if ( verbatimFlag )
1738         {
1739             verbatimContent( text );
1740         }
1741         else
1742         {
1743             content( text );
1744         }
1745     }
1746 
1747     /** {@inheritDoc} */
1748     public void comment( String comment )
1749     {
1750         if ( comment != null )
1751         {
1752             String originalComment = comment;
1753 
1754             // http://www.w3.org/TR/2000/REC-xml-20001006#sec-comments
1755             while ( comment.contains( "--" ) )
1756             {
1757                 comment = comment.replace( "--", "- -" );
1758             }
1759 
1760             if ( comment.endsWith( "-" ) )
1761             {
1762                 comment += " ";
1763             }
1764 
1765             if ( !originalComment.equals( comment ) )
1766             {
1767                 String msg = "Modified invalid comment: '" + originalComment + "' to '" + comment + "'";
1768                 logMessage( "modifiedComment", msg );
1769             }
1770 
1771             StringBuilder buffer = new StringBuilder( comment.length() + 7 );
1772 
1773             buffer.append( LESS_THAN ).append( BANG ).append( MINUS ).append( MINUS );
1774             buffer.append( comment );
1775             buffer.append( MINUS ).append( MINUS ).append( GREATER_THAN );
1776 
1777             markup( buffer.toString() );
1778         }
1779     }
1780 
1781     /**
1782      * {@inheritDoc}
1783      *
1784      * Unknown events just log a warning message but are ignored otherwise.
1785      * @see org.apache.maven.doxia.sink.Sink#unknown(String,Object[],SinkEventAttributes)
1786      */
1787     public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
1788     {
1789         String msg = "Unknown Sink event: '" + name + "', ignoring!";
1790         logMessage( "unknownEvent", msg );
1791     }
1792 
1793     // -----------------------------------------------------------------------
1794 
1795     /**
1796      * Write text to output, preserving white space.
1797      *
1798      * @param text The text to write.
1799      */
1800     protected void markup( String text )
1801     {
1802         if ( !skip )
1803         {
1804             out.write( text );
1805         }
1806     }
1807 
1808     /**
1809      * Write SGML escaped text to output, not preserving white space.
1810      *
1811      * @param text The text to write.
1812      */
1813     protected void content( String text )
1814     {
1815         if ( !skip )
1816         {
1817             out.write( escapeHTML( text, true ) );
1818         }
1819     }
1820 
1821     /**
1822      * Write SGML escaped text to output, preserving white space.
1823      *
1824      * @param text The text to write.
1825      */
1826     protected void verbatimContent( String text )
1827     {
1828         if ( !skip )
1829         {
1830             out.write( escapeHTML( text, true ) );
1831         }
1832     }
1833 
1834     // -----------------------------------------------------------------------
1835 
1836     /**
1837      * {@inheritDoc}
1838      */
1839     public void flush()
1840     {
1841         out.flush();
1842     }
1843 
1844     /**
1845      * {@inheritDoc}
1846      */
1847     public void close()
1848     {
1849         out.close();
1850 
1851         if ( getLog().isWarnEnabled() && this.warnMessages != null )
1852         {
1853             for ( Map.Entry<String, Set<String>> entry : this.warnMessages.entrySet() )
1854             {
1855                 for ( String msg : entry.getValue() )
1856                 {
1857                     getLog().warn( msg );
1858                 }
1859             }
1860 
1861             this.warnMessages = null;
1862         }
1863     }
1864 
1865     /** {@inheritDoc} */
1866     protected void write( String text )
1867     {
1868         markup( unifyEOLs( text ) );
1869     }
1870 
1871     /**
1872      * <p>Setter for the field <code>skip</code>.</p>
1873      *
1874      * @param skip the skip to set.
1875      * @since 1.1
1876      */
1877     public void setSkip( boolean skip )
1878     {
1879         this.skip = skip;
1880     }
1881 
1882     /**
1883      * If debug mode is enabled, log the <code>msg</code> as is, otherwise add unique msg in <code>warnMessages</code>.
1884      *
1885      * @param key not null
1886      * @param msg not null
1887      * @see #close()
1888      * @since 1.1.1
1889      */
1890     private void logMessage( String key, String msg )
1891     {
1892         msg = "[Docbook Sink] " + msg;
1893         if ( getLog().isDebugEnabled() )
1894         {
1895             getLog().debug( msg );
1896 
1897             return;
1898         }
1899 
1900         if ( warnMessages == null )
1901         {
1902             warnMessages = new HashMap<>();
1903         }
1904 
1905         Set<String> set = warnMessages.get( key );
1906         if ( set == null )
1907         {
1908             set = new TreeSet<>();
1909         }
1910         set.add( msg );
1911         warnMessages.put( key, set );
1912     }
1913 }