[DOXIA-575] Add support for (X)HTML5
This closes #16
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/markup/HtmlMarkup.java b/doxia-core/src/main/java/org/apache/maven/doxia/markup/HtmlMarkup.java
index 356e790..da7b1b1 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/markup/HtmlMarkup.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/markup/HtmlMarkup.java
@@ -25,11 +25,13 @@
/**
* List of <code>Html</code> tags.
* <p>
- * This should contain all valid XHTML 1.0 tags, comprising the tags in
- * {@link javax.swing.text.html.HTML.Tag} plus several others.
+ * This should contain all valid XHTML 1.0 and HTML5 tags, comprising the tags
+ * in {@link javax.swing.text.html.HTML.Tag} plus several others.
* </p>
*
- * @see <a href="http://www.w3.org/TR/html401/index/elements.html">http://www.w3.org/TR/html401/index/elements.html</a>
+ * @see <a href=
+ * "https://www.w3.org/TR/2012/WD-html-markup-20121011/elements-by-function.html">
+ * https://www.w3.org/TR/2012/WD-html-markup-20121011/elements-by-function.html</a>
*
* @author ltheussl
* @version $Id$
@@ -101,6 +103,39 @@
/** Xhtml tag for <code>area</code>. */
Tag AREA = Tag.AREA;
+ /** Html5 tag for <code>article</code>. */
+ Tag ARTICLE = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "article";
+ }
+ };
+
+ /** Html5 tag for <code>aside</code>. */
+ Tag ASIDE = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "aside";
+ }
+ };
+
+ /** Html5 tag for <code>audio</code>. */
+ Tag AUDIO = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "audio";
+ }
+ };
+
/** Xhtml tag for <code>b</code>. */
Tag B = Tag.B;
@@ -110,6 +145,17 @@
/** Xhtml tag for <code>basefont</code>. */
Tag BASEFONT = Tag.BASEFONT;
+ /** Html5 tag for <code>bdi</code>. */
+ Tag BDI = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "bdi";
+ }
+ };
+
/** Xhtml tag for <code>bdo</code>. */
Tag BDO = new Tag()
{
@@ -144,6 +190,17 @@
}
};
+ /** Html5 tag for <code>canvas</code>. */
+ Tag CANVAS = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "canvas";
+ }
+ };
+
/** Xhtml tag for <code>caption</code>. */
Tag CAPTION = Tag.CAPTION;
@@ -178,6 +235,39 @@
}
};
+ /** Html5 tag for <code>command</code>. */
+ Tag COMMAND = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "command";
+ }
+ };
+
+ /** Html5 tag for <code>data</code>. */
+ Tag DATA = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "data";
+ }
+ };
+
+ /** Html5 tag for <code>datalist</code>. */
+ Tag DATALIST = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "datalist";
+ }
+ };
+
/** Xhtml tag for <code>dd</code>. */
Tag DD = Tag.DD;
@@ -192,9 +282,31 @@
}
};
+ /** Html5 tag for <code>details</code>. */
+ Tag DETAILS = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "details";
+ }
+ };
+
/** Xhtml tag for <code>dfn</code>. */
Tag DFN = Tag.DFN;
+ /** Html5 tag for <code>dialog</code>. */
+ Tag DIALOG = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "dialog";
+ }
+ };
+
/** Xhtml tag for <code>dir</code>. */
Tag DIR = Tag.DIR;
@@ -210,6 +322,17 @@
/** Xhtml tag for <code>em</code>. */
Tag EM = Tag.EM;
+ /** Html5 tag for <code>embed</code>. */
+ Tag EMBED = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "embed";
+ }
+ };
+
/** Xhtml tag for <code>fieldset</code>. */
Tag FIELDSET = new Tag()
{
@@ -221,9 +344,42 @@
}
};
+ /** Html5 tag for <code>figcaption</code>. */
+ Tag FIGCAPTION = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "figcaption";
+ }
+ };
+
+ /** Html5 tag for <code>figure</code>. */
+ Tag FIGURE = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "figure";
+ }
+ };
+
/** Xhtml tag for <code>font</code>. */
Tag FONT = Tag.FONT;
+ /** Html5 tag for <code>footer</code>. */
+ Tag FOOTER = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "footer";
+ }
+ };
+
/** Xhtml tag for <code>form</code>. */
Tag FORM = Tag.FORM;
@@ -254,6 +410,28 @@
/** Xhtml tag for <code>head</code>. */
Tag HEAD = Tag.HEAD;
+ /** Html5 tag for <code>header</code>. */
+ Tag HEADER = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "header";
+ }
+ };
+
+ /** Html5 tag for <code>hgroup</code>. */
+ Tag HGROUP = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "hgroup";
+ }
+ };
+
/** Xhtml tag for <code>hr</code>. */
Tag HR = Tag.HR;
@@ -328,12 +506,56 @@
/** Xhtml tag for <code>map</code>. */
Tag MAP = Tag.MAP;
+ /** Html5 tag for <code>main</code>. */
+ Tag MAIN = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "main";
+ }
+ };
+
+ /** Html5 tag for <code>mark</code>. */
+ Tag MARK = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "mark";
+ }
+ };
+
/** Xhtml tag for <code>menu</code>. */
Tag MENU = Tag.MENU;
/** Xhtml tag for <code>meta</code>. */
Tag META = Tag.META;
+ /** Html5 tag for <code>meter</code>. */
+ Tag METER = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "meter";
+ }
+ };
+
+ /** Html5 tag for <code>nav</code>. */
+ Tag NAV = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "nav";
+ }
+ };
+
/** Xhtml tag for <code>noframes</code>. */
Tag NOFRAMES = Tag.NOFRAMES;
@@ -368,15 +590,48 @@
/** Xhtml tag for <code>option</code>. */
Tag OPTION = Tag.OPTION;
+ /** Html5 tag for <code>output</code>. */
+ Tag OUTPUT = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "output";
+ }
+ };
+
/** Xhtml tag for <code>p</code>. */
Tag P = Tag.P;
/** Xhtml tag for <code>param</code>. */
Tag PARAM = Tag.PARAM;
+ /** Html5 tag for <code>picture</code>. */
+ Tag PICTURE = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "picture";
+ }
+ };
+
/** Xhtml tag for <code>pre</code>. */
Tag PRE = Tag.PRE;
+ /** Html5 tag for <code>progress</code>. */
+ Tag PROGRESS = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "progress";
+ }
+ };
+
/** Xhtml tag for <code>q</code>. */
Tag Q = new Tag()
{
@@ -388,6 +643,61 @@
}
};
+ /** Html5 tag for <code>rb</code>. */
+ Tag RB = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "rb";
+ }
+ };
+
+ /** Html5 tag for <code>rp</code>. */
+ Tag RP = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "rp";
+ }
+ };
+
+ /** Html5 tag for <code>rt</code>. */
+ Tag RT = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "rt";
+ }
+ };
+
+ /** Html5 tag for <code>rtc</code>. */
+ Tag RTC = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "rtc";
+ }
+ };
+
+ /** Html5 tag for <code>ruby</code>. */
+ Tag RUBY = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "ruby";
+ }
+ };
+
/** Xhtml tag for <code>s</code>. */
Tag S = Tag.S;
@@ -397,12 +707,34 @@
/** Xhtml tag for <code>script</code>. */
Tag SCRIPT = Tag.SCRIPT;
+ /** Html5 tag for <code>section</code>. */
+ Tag SECTION = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "section";
+ }
+ };
+
/** Xhtml tag for <code>select</code>. */
Tag SELECT = Tag.SELECT;
/** Xhtml tag for <code>small</code>. */
Tag SMALL = Tag.SMALL;
+ /** Html5 tag for <code>source</code>. */
+ Tag SOURCE = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "source";
+ }
+ };
+
/** Xhtml tag for <code>span</code>. */
Tag SPAN = Tag.SPAN;
@@ -418,6 +750,17 @@
/** Xhtml tag for <code>sub</code>. */
Tag SUB = Tag.SUB;
+ /** Html5 tag for <code>summary</code>. */
+ Tag SUMMARY = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "summary";
+ }
+ };
+
/** Xhtml tag for <code>sup</code>. */
Tag SUP = Tag.SUP;
@@ -438,6 +781,17 @@
/** Xhtml tag for <code>td</code>. */
Tag TD = Tag.TD;
+ /** Html5 tag for <code>template</code>. */
+ Tag TEMPLATE = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "template";
+ }
+ };
+
/** Xhtml tag for <code>textarea</code>. */
Tag TEXTAREA = Tag.TEXTAREA;
@@ -466,12 +820,34 @@
}
};
+ /** Html5 tag for <code>time</code>. */
+ Tag TIME = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "time";
+ }
+ };
+
/** Xhtml tag for <code>title</code>. */
Tag TITLE = Tag.TITLE;
/** Xhtml tag for <code>tr</code>. */
Tag TR = Tag.TR;
+ /** Html5 tag for <code>track</code>. */
+ Tag TRACK = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "track";
+ }
+ };
+
/** Xhtml tag for <code>tt</code>. */
Tag TT = Tag.TT;
@@ -483,4 +859,27 @@
/** Xhtml tag for <code>var</code>. */
Tag VAR = Tag.VAR ;
+
+ /** Html5 tag for <code>video</code>. */
+ Tag VIDEO = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "video";
+ }
+ };
+
+ /** Html5 tag for <code>wbr</code>. */
+ Tag WBR = new Tag()
+ {
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return "wbr";
+ }
+ };
+
}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java
new file mode 100644
index 0000000..70dac8d
--- /dev/null
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/parser/Xhtml5BaseParser.java
@@ -0,0 +1,1308 @@
+package org.apache.maven.doxia.parser;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TreeSet;
+
+import javax.swing.text.html.HTML.Attribute;
+
+import org.apache.maven.doxia.macro.MacroExecutionException;
+import org.apache.maven.doxia.markup.HtmlMarkup;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.SinkEventAttributes;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+import org.apache.maven.doxia.util.DoxiaUtils;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Common base parser for xhtml5 events.
+ */
+public class Xhtml5BaseParser
+ extends AbstractXmlParser
+ implements HtmlMarkup
+{
+ /**
+ * True if a <script></script> or <style></style> block is read. CDATA sections within are
+ * handled as rawText.
+ */
+ private boolean scriptBlock;
+
+ /** Used to distinguish <a href=""> from <a name="">. */
+ private boolean isLink;
+
+ /** Used to distinguish <a href=""> from <a name="">. */
+ private boolean isAnchor;
+
+ /** Used for nested lists. */
+ private int orderedListDepth = 0;
+
+ /** Counts section level. */
+ private int sectionLevel;
+
+ /** Counts heading level. */
+ private int headingLevel;
+
+ /** Verbatim flag, true whenever we are inside a <pre> tag. */
+ private boolean inVerbatim;
+
+ /** Used to keep track of closing tags for content events */
+ private Stack<String> divStack = new Stack<String>();
+
+ /** Used to wrap the definedTerm with its definition, even when one is omitted */
+ boolean hasDefinitionListItem = false;
+
+ /** Map of warn messages with a String as key to describe the error type and a Set as value.
+ * Using to reduce warn messages. */
+ private Map<String, Set<String>> warnMessages;
+
+ /** {@inheritDoc} */
+ @Override
+ public void parse( Reader source, Sink sink )
+ throws ParseException
+ {
+ init();
+
+ try
+ {
+ super.parse( source, sink );
+ }
+ finally
+ {
+ logWarnings();
+
+ setSecondParsing( false );
+ init();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Adds all XHTML (HTML 5.2) entities to the parser so that they can be recognized and resolved
+ * without additional DTD.
+ */
+ @Override
+ protected void initXmlParser( XmlPullParser parser )
+ throws XmlPullParserException
+ {
+ super.initXmlParser( parser );
+ }
+
+ /**
+ * <p>
+ * Goes through a common list of possible html5 start tags. These include only tags that can go into
+ * the body of an xhtml5 document and so should be re-usable by different xhtml-based parsers.
+ * </p>
+ * <p>
+ * The currently handled tags are:
+ * </p>
+ * <p>
+ * <code>
+ * <article>, <nav>, <aside>, <section>, <h2>, <h3>, <h4>,
+ * <h5>, <h6>, <header>, <main>, <footer>, <em>, <strong>,
+ * <small>, <s>, <cite>, <q>, <dfn>, <abbr>, <i>,
+ * <b>, <code>, <samp>, <kbd>, <sub>, <sup>, <u>,
+ * <mark>, <ruby>, <rb>, <rt>, <rtc>, <rp>, <bdi>,
+ * <bdo>, <span>, <ins>, <del>, <p>, <pre>, <ul>,
+ * <ol>, <li>, <dl>, <dt>, <dd>, <a>, <table>,
+ * <tr>, <th>, <td>, <caption>, <br/>, <wbr/>, <hr/>,
+ * <img/>.
+ * </code>
+ * </p>
+ *
+ * @param parser A parser.
+ * @param sink the sink to receive the events.
+ * @return True if the event has been handled by this method, i.e. the tag was recognized, false otherwise.
+ */
+ protected boolean baseStartTag( XmlPullParser parser, Sink sink )
+ {
+ boolean visited = true;
+
+ SinkEventAttributeSet attribs = getAttributesFromParser( parser );
+
+ if ( parser.getName().equals( HtmlMarkup.ARTICLE.toString() ) )
+ {
+ sink.article( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.NAV.toString() ) )
+ {
+ sink.navigation( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.ASIDE.toString() ) )
+ {
+ sink.sidebar( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SECTION.toString() ) )
+ {
+ handleSectionStart( sink, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H2.toString() ) )
+ {
+ handleHeadingStart( sink, Sink.SECTION_LEVEL_1, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H3.toString() ) )
+ {
+ handleHeadingStart( sink, Sink.SECTION_LEVEL_2, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H4.toString() ) )
+ {
+ handleHeadingStart( sink, Sink.SECTION_LEVEL_3, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H5.toString() ) )
+ {
+ handleHeadingStart( sink, Sink.SECTION_LEVEL_4, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H6.toString() ) )
+ {
+ handleHeadingStart( sink, Sink.SECTION_LEVEL_5, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.HEADER.toString() ) )
+ {
+ sink.header( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.MAIN.toString() ) )
+ {
+ sink.content( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.FOOTER.toString() ) )
+ {
+ sink.footer( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.EM.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.EMPHASIS );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.STRONG.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.STRONG );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SMALL.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.SMALL );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.S.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.LINE_THROUGH );
+ sink.inline( attribs );
+ /* deprecated line-through support */
+ }
+ else if ( parser.getName().equals( HtmlMarkup.CITE.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.CITATION );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.Q.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.QUOTE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DFN.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.DEFINITION );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.ABBR.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.ABBREVIATION );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.I.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.ITALIC );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.B.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.BOLD );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.CODE.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.CODE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.VAR.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.VARIABLE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.SAMPLE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.KBD.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.KEYBOARD );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SUP.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.SUPERSCRIPT );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SUB.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.SUBSCRIPT );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.U.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.ANNOTATION );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.MARK.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.HIGHLIGHT );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RUBY.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.RUBY );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RB.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.RUBY_BASE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RT.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.RUBY_TEXT );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RTC.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.RUBY_TEXT_CONTAINER );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RP.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.RUBY_PARANTHESES );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.BDI.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.BIDIRECTIONAL_ISOLATION );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.BDO.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.BIDIRECTIONAL_OVERRIDE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SPAN.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.PHRASE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.INS.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.INSERT );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DEL.toString() ) )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.DELETE );
+ sink.inline( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.P.toString() ) )
+ {
+ handlePStart( sink, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DIV.toString() ) )
+ {
+ handleDivStart( parser, attribs, sink );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.PRE.toString() ) )
+ {
+ handlePreStart( attribs, sink );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.UL.toString() ) )
+ {
+ sink.list( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.OL.toString() ) )
+ {
+ handleOLStart( parser, sink, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.LI.toString() ) )
+ {
+ handleLIStart( sink, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DL.toString() ) )
+ {
+ sink.definitionList( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DT.toString() ) )
+ {
+ if ( hasDefinitionListItem )
+ {
+ // close previous listItem
+ sink.definitionListItem_();
+ }
+ sink.definitionListItem( attribs );
+ hasDefinitionListItem = true;
+ sink.definedTerm( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DD.toString() ) )
+ {
+ if ( !hasDefinitionListItem )
+ {
+ sink.definitionListItem( attribs );
+ }
+ sink.definition( attribs );
+ }
+ else if ( ( parser.getName().equals( HtmlMarkup.FIGURE.toString() ) ) )
+ {
+ sink.figure( attribs );
+ }
+ else if ( ( parser.getName().equals( HtmlMarkup.FIGCAPTION.toString() ) ) )
+ {
+ sink.figureCaption( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
+ {
+ handleAStart( parser, sink, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TABLE.toString() ) )
+ {
+ handleTableStart( sink, attribs, parser );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TR.toString() ) )
+ {
+ sink.tableRow( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TH.toString() ) )
+ {
+ sink.tableHeaderCell( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TD.toString() ) )
+ {
+ sink.tableCell( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.CAPTION.toString() ) )
+ {
+ sink.tableCaption( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.BR.toString() ) )
+ {
+ sink.lineBreak( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.WBR.toString() ) )
+ {
+ sink.lineBreakOpportunity( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.HR.toString() ) )
+ {
+ sink.horizontalRule( attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.IMG.toString() ) )
+ {
+ handleImgStart( parser, sink, attribs );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SCRIPT.toString() )
+ || parser.getName().equals( HtmlMarkup.STYLE.toString() ) )
+ {
+ handleUnknown( parser, sink, TAG_TYPE_START );
+ scriptBlock = true;
+ }
+ else
+ {
+ visited = false;
+ }
+
+ return visited;
+ }
+
+ /**
+ * <p>
+ * Goes through a common list of possible html end tags.
+ * These should be re-usable by different xhtml-based parsers.
+ * The tags handled here are the same as for {@link #baseStartTag(XmlPullParser,Sink)},
+ * except for the empty elements ({@code<br/>, <hr/>, <img/>}).
+ * </p>
+ *
+ * @param parser A parser.
+ * @param sink the sink to receive the events.
+ * @return True if the event has been handled by this method, false otherwise.
+ */
+ protected boolean baseEndTag( XmlPullParser parser, Sink sink )
+ {
+ boolean visited = true;
+
+ if ( parser.getName().equals( HtmlMarkup.P.toString() ) )
+ {
+ sink.paragraph_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DIV.toString() ) )
+ {
+ handleDivEnd( sink );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.PRE.toString() ) )
+ {
+ verbatim_();
+
+ sink.verbatim_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.UL.toString() ) )
+ {
+ sink.list_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.OL.toString() ) )
+ {
+ sink.numberedList_();
+ orderedListDepth--;
+ }
+ else if ( parser.getName().equals( HtmlMarkup.LI.toString() ) )
+ {
+ handleListItemEnd( sink );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DL.toString() ) )
+ {
+ if ( hasDefinitionListItem )
+ {
+ sink.definitionListItem_();
+ hasDefinitionListItem = false;
+ }
+ sink.definitionList_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DT.toString() ) )
+ {
+ sink.definedTerm_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DD.toString() ) )
+ {
+ sink.definition_();
+ sink.definitionListItem_();
+ hasDefinitionListItem = false;
+ }
+ else if ( ( parser.getName().equals( HtmlMarkup.FIGURE.toString() ) ) )
+ {
+ sink.figure_();
+ }
+ else if ( ( parser.getName().equals( HtmlMarkup.FIGCAPTION.toString() ) ) )
+ {
+ sink.figureCaption_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
+ {
+ handleAEnd( sink );
+ }
+
+ else if ( parser.getName().equals( HtmlMarkup.EM.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.STRONG.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SMALL.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.S.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.CITE.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.Q.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DFN.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.ABBR.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.I.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.B.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.CODE.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.VAR.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.KBD.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SUP.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SUB.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.U.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.MARK.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RUBY.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RB.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RT.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RTC.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.RP.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.BDI.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.BDO.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SPAN.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.INS.toString() ) )
+ {
+ sink.inline_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.DEL.toString() ) )
+ {
+ sink.inline_();
+ }
+
+ // ----------------------------------------------------------------------
+ // Tables
+ // ----------------------------------------------------------------------
+
+ else if ( parser.getName().equals( HtmlMarkup.TABLE.toString() ) )
+ {
+ sink.tableRows_();
+
+ sink.table_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TR.toString() ) )
+ {
+ sink.tableRow_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TH.toString() ) )
+ {
+ sink.tableHeaderCell_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.TD.toString() ) )
+ {
+ sink.tableCell_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.CAPTION.toString() ) )
+ {
+ sink.tableCaption_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.ARTICLE.toString() ) )
+ {
+ sink.article_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.NAV.toString() ) )
+ {
+ sink.navigation_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.ASIDE.toString() ) )
+ {
+ sink.sidebar_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SECTION.toString() ) )
+ {
+ handleSectionEnd( sink );
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H2.toString() ) )
+ {
+ sink.sectionTitle1_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H3.toString() ) )
+ {
+ sink.sectionTitle2_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H4.toString() ) )
+ {
+ sink.sectionTitle3_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H5.toString() ) )
+ {
+ sink.sectionTitle4_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.H6.toString() ) )
+ {
+ sink.sectionTitle5_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.HEADER.toString() ) )
+ {
+ sink.header_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.MAIN.toString() ) )
+ {
+ sink.content_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.FOOTER.toString() ) )
+ {
+ sink.footer_();
+ }
+ else if ( parser.getName().equals( HtmlMarkup.SCRIPT.toString() )
+ || parser.getName().equals( HtmlMarkup.STYLE.toString() ) )
+ {
+ handleUnknown( parser, sink, TAG_TYPE_END );
+
+ scriptBlock = false;
+ }
+ else
+ {
+ visited = false;
+ }
+
+ return visited;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Just calls {@link #baseStartTag(XmlPullParser,Sink)}, this should be
+ * overridden by implementing parsers to include additional tags.
+ */
+ protected void handleStartTag( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException, MacroExecutionException
+ {
+ if ( !baseStartTag( parser, sink ) )
+ {
+ if ( getLog().isWarnEnabled() )
+ {
+ String position = "[" + parser.getLineNumber() + ":"
+ + parser.getColumnNumber() + "]";
+ String tag = "<" + parser.getName() + ">";
+
+ getLog().warn( "Unrecognized xml tag: " + tag + " at " + position );
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Just calls {@link #baseEndTag(XmlPullParser,Sink)}, this should be
+ * overridden by implementing parsers to include additional tags.
+ */
+ protected void handleEndTag( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException, MacroExecutionException
+ {
+ if ( !baseEndTag( parser, sink ) )
+ {
+ // unrecognized tag is already logged in StartTag
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void handleText( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException
+ {
+ String text = getText( parser );
+
+ /*
+ * NOTE: Don't do any whitespace trimming here. Whitespace normalization has already been performed by the
+ * parser so any whitespace that makes it here is significant.
+ *
+ * NOTE: text within script tags is ignored, scripting code should be embedded in CDATA.
+ */
+ if ( StringUtils.isNotEmpty( text ) && !isScriptBlock() )
+ {
+ sink.text( text );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void handleComment( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException
+ {
+ String text = getText( parser );
+
+ if ( "PB".equals( text.trim() ) )
+ {
+ sink.pageBreak();
+ }
+ else
+ {
+ if ( isEmitComments() )
+ {
+ sink.comment( text );
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void handleCdsect( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException
+ {
+ String text = getText( parser );
+
+ if ( isScriptBlock() )
+ {
+ sink.unknown( CDATA, new Object[] { Integer.valueOf( CDATA_TYPE ), text}, null );
+ }
+ else
+ {
+ sink.text( text );
+ }
+ }
+
+ /**
+ * Make sure sections are nested consecutively.
+ *
+ * <p>
+ * HTML5 heading tags H1 to H6 imply sections where they are not
+ * present, that means we have to open close any sections that
+ * are missing in between.
+ * </p>
+ *
+ * <p>
+ * For instance, if the following sequence is parsed:
+ * </p>
+ * <pre>
+ * <h3></h3>
+ * <h6></h6>
+ * </pre>
+ * <p>
+ * we have to insert two section starts before we open the <code><h6></code>.
+ * In the following sequence
+ * </p>
+ * <pre>
+ * <h6></h6>
+ * <h3></h3>
+ * </pre>
+ * <p>
+ * we have to close two sections before we open the <code><h3></code>.
+ * </p>
+ *
+ * <p>The current level is set to newLevel afterwards.</p>
+ *
+ * @param newLevel the new section level, all upper levels have to be closed.
+ * @param sink the sink to receive the events.
+ */
+ protected void consecutiveSections( int newLevel, Sink sink, SinkEventAttributeSet attribs )
+ {
+ closeOpenSections( newLevel, sink );
+ openMissingSections( newLevel, sink );
+
+ this.headingLevel = newLevel;
+ }
+
+ /**
+ * Close open sections.
+ *
+ * @param newLevel the new section level, all upper levels have to be closed.
+ * @param sink the sink to receive the events.
+ */
+ private void closeOpenSections( int newLevel, Sink sink )
+ {
+ while ( this.headingLevel >= newLevel
+ && this.sectionLevel < headingLevel )
+ {
+ if ( headingLevel == Sink.SECTION_LEVEL_5 )
+ {
+ sink.section5_();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_4 )
+ {
+ sink.section4_();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_3 )
+ {
+ sink.section3_();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_2 )
+ {
+ sink.section2_();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_1 )
+ {
+ sink.section1_();
+ }
+
+ this.headingLevel--;
+ }
+ }
+
+ /**
+ * Open missing sections.
+ *
+ * @param newLevel the new section level, all lower levels have to be opened.
+ * @param sink the sink to receive the events.
+ */
+ private void openMissingSections( int newLevel, Sink sink )
+ {
+ while ( this.headingLevel < newLevel
+ && this.sectionLevel < newLevel )
+ {
+ this.headingLevel++;
+
+ if ( headingLevel == Sink.SECTION_LEVEL_5 )
+ {
+ sink.section5();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_4 )
+ {
+ sink.section4();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_3 )
+ {
+ sink.section3();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_2 )
+ {
+ sink.section2();
+ }
+ else if ( headingLevel == Sink.SECTION_LEVEL_1 )
+ {
+ sink.section1();
+ }
+ }
+ }
+
+ /**
+ * Return the current section level.
+ *
+ * @return the current section level.
+ */
+ protected int getSectionLevel()
+ {
+ return this.headingLevel;
+ }
+
+ /**
+ * Set the current section level.
+ *
+ * @param newLevel the new section level.
+ */
+ protected void setSectionLevel( int newLevel )
+ {
+ this.headingLevel = newLevel;
+ }
+
+ /**
+ * Stop verbatim mode.
+ */
+ protected void verbatim_()
+ {
+ this.inVerbatim = false;
+ }
+
+ /**
+ * Start verbatim mode.
+ */
+ protected void verbatim()
+ {
+ this.inVerbatim = true;
+ }
+
+ /**
+ * Checks if we are currently inside a <pre> tag.
+ *
+ * @return true if we are currently in verbatim mode.
+ */
+ protected boolean isVerbatim()
+ {
+ return this.inVerbatim;
+ }
+
+ /**
+ * Checks if we are currently inside a <script> tag.
+ *
+ * @return true if we are currently inside <code><script></code> tags.
+ *
+ * @since 1.1.1.
+ */
+ protected boolean isScriptBlock()
+ {
+ return this.scriptBlock;
+ }
+
+ /**
+ * Checks if the given id is a valid Doxia id and if not, returns a transformed one.
+ *
+ * @param id The id to validate.
+ * @return A transformed id or the original id if it was already valid.
+ * @see DoxiaUtils#encodeId(String)
+ */
+ protected String validAnchor( String id )
+ {
+ if ( !DoxiaUtils.isValidId( id ) )
+ {
+ String linkAnchor = DoxiaUtils.encodeId( id, true );
+
+ String msg = "Modified invalid link: '" + id + "' to '" + linkAnchor + "'";
+ logMessage( "modifiedLink", msg );
+
+ return linkAnchor;
+ }
+
+ return id;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void init()
+ {
+ super.init();
+
+ this.scriptBlock = false;
+ this.isLink = false;
+ this.isAnchor = false;
+ this.orderedListDepth = 0;
+ this.headingLevel = 0;
+ this.inVerbatim = false;
+ this.warnMessages = null;
+ }
+
+ private void handleAEnd( Sink sink )
+ {
+ if ( isLink )
+ {
+ sink.link_();
+ isLink = false;
+ }
+ else if ( isAnchor )
+ {
+ sink.anchor_();
+ isAnchor = false;
+ }
+ }
+
+ private void handleAStart( XmlPullParser parser, Sink sink, SinkEventAttributeSet attribs )
+ {
+ String href = parser.getAttributeValue( null, Attribute.HREF.toString() );
+
+ if ( href != null )
+ {
+ int hashIndex = href.indexOf( '#' );
+ if ( hashIndex != -1 && !DoxiaUtils.isExternalLink( href ) )
+ {
+ String hash = href.substring( hashIndex + 1 );
+
+ if ( !DoxiaUtils.isValidId( hash ) )
+ {
+ href = href.substring( 0, hashIndex ) + "#" + DoxiaUtils.encodeId( hash, true );
+
+ String msg = "Modified invalid link: '" + hash + "' to '" + href + "'";
+ logMessage( "modifiedLink", msg );
+ }
+ }
+ sink.link( href, attribs );
+ isLink = true;
+ }
+ else
+ {
+ String name = parser.getAttributeValue( null, Attribute.NAME.toString() );
+
+ if ( name != null )
+ {
+ sink.anchor( validAnchor( name ), attribs );
+ isAnchor = true;
+ }
+ else
+ {
+ String id = parser.getAttributeValue( null, Attribute.ID.toString() );
+ if ( id != null )
+ {
+ sink.anchor( validAnchor( id ), attribs );
+ isAnchor = true;
+ }
+ }
+ }
+ }
+
+ private boolean handleDivStart( XmlPullParser parser, SinkEventAttributeSet attribs, Sink sink )
+ {
+ String divclass = parser.getAttributeValue( null, Attribute.CLASS.toString() );
+
+ this.divStack.push( divclass );
+
+ if ( "content".equals( divclass ) )
+ {
+ SinkEventAttributeSet atts = new SinkEventAttributeSet( attribs );
+ atts.removeAttribute( SinkEventAttributes.CLASS );
+ sink.content( atts );
+ }
+ if ( "source".equals( divclass ) )
+ {
+ return false;
+ }
+ else
+ {
+ sink.division( attribs );
+ }
+
+ return true;
+ }
+
+ private boolean handleDivEnd( Sink sink )
+ {
+ String divclass = divStack.pop();
+
+ if ( "content".equals( divclass ) )
+ {
+ sink.content_();
+ }
+ if ( "source".equals( divclass ) )
+ {
+ return false;
+ }
+ else
+ {
+ sink.division_();
+ }
+
+ return true;
+ }
+
+ private void handleImgStart( XmlPullParser parser, Sink sink, SinkEventAttributeSet attribs )
+ {
+ String src = parser.getAttributeValue( null, Attribute.SRC.toString() );
+
+ if ( src != null )
+ {
+ sink.figureGraphics( src, attribs );
+ }
+ }
+
+ private void handleLIStart( Sink sink, SinkEventAttributeSet attribs )
+ {
+ if ( orderedListDepth == 0 )
+ {
+ sink.listItem( attribs );
+ }
+ else
+ {
+ sink.numberedListItem( attribs );
+ }
+ }
+
+ private void handleListItemEnd( Sink sink )
+ {
+ if ( orderedListDepth == 0 )
+ {
+ sink.listItem_();
+ }
+ else
+ {
+ sink.numberedListItem_();
+ }
+ }
+
+ private void handleOLStart( XmlPullParser parser, Sink sink, SinkEventAttributeSet attribs )
+ {
+ int numbering = Sink.NUMBERING_DECIMAL;
+ // this will have to be generalized if we handle styles
+ String style = parser.getAttributeValue( null, Attribute.STYLE.toString() );
+
+ if ( style != null )
+ {
+ if ( "list-style-type: upper-alpha".equals( style ) )
+ {
+ numbering = Sink.NUMBERING_UPPER_ALPHA;
+ }
+ else if ( "list-style-type: lower-alpha".equals( style ) )
+ {
+ numbering = Sink.NUMBERING_LOWER_ALPHA;
+ }
+ else if ( "list-style-type: upper-roman".equals( style ) )
+ {
+ numbering = Sink.NUMBERING_UPPER_ROMAN;
+ }
+ else if ( "list-style-type: lower-roman".equals( style ) )
+ {
+ numbering = Sink.NUMBERING_LOWER_ROMAN;
+ }
+ else if ( "list-style-type: decimal".equals( style ) )
+ {
+ numbering = Sink.NUMBERING_DECIMAL;
+ }
+ }
+
+ sink.numberedList( numbering, attribs );
+ orderedListDepth++;
+ }
+
+ private void handlePStart( Sink sink, SinkEventAttributeSet attribs )
+ {
+ sink.paragraph( attribs );
+ }
+
+ /*
+ * The PRE element tells visual user agents that the enclosed text is
+ * "preformatted". When handling preformatted text, visual user agents:
+ * - May leave white space intact.
+ * - May render text with a fixed-pitch font.
+ * - May disable automatic word wrap.
+ * - Must not disable bidirectional processing.
+ * Non-visual user agents are not required to respect extra white space
+ * in the content of a PRE element.
+ */
+ private void handlePreStart( SinkEventAttributeSet attribs, Sink sink )
+ {
+ verbatim();
+ sink.verbatim( attribs );
+ }
+
+ private void handleSectionStart( Sink sink, SinkEventAttributeSet attribs )
+ {
+ sink.section( ++sectionLevel, attribs );
+ }
+
+ private void handleHeadingStart( Sink sink, int level, SinkEventAttributeSet attribs )
+ {
+ consecutiveSections( level, sink, attribs );
+ sink.sectionTitle( level, attribs );
+ }
+
+ private void handleSectionEnd( Sink sink )
+ {
+ closeOpenSections( sectionLevel, sink );
+ this.headingLevel = 0;
+
+ sink.section_( sectionLevel-- );
+ }
+
+ private void handleTableStart( Sink sink, SinkEventAttributeSet attribs, XmlPullParser parser )
+ {
+ sink.table( attribs );
+ String border = parser.getAttributeValue( null, Attribute.BORDER.toString() );
+ boolean grid = true;
+
+ if ( border == null || "0".equals( border ) )
+ {
+ grid = false;
+ }
+
+ String align = parser.getAttributeValue( null, Attribute.ALIGN.toString() );
+ int[] justif = {Sink.JUSTIFY_LEFT};
+
+ if ( "center".equals( align ) )
+ {
+ justif[0] = Sink.JUSTIFY_CENTER;
+ }
+ else if ( "right".equals( align ) )
+ {
+ justif[0] = Sink.JUSTIFY_RIGHT;
+ }
+
+ sink.tableRows( justif, grid );
+ }
+
+ /**
+ * If debug mode is enabled, log the <code>msg</code> as is, otherwise add unique msg in <code>warnMessages</code>.
+ *
+ * @param key not null
+ * @param msg not null
+ * @see #parse(Reader, Sink)
+ * @since 1.1.1
+ */
+ private void logMessage( String key, String msg )
+ {
+ final String log = "[XHTML Parser] " + msg;
+ if ( getLog().isDebugEnabled() )
+ {
+ getLog().debug( log );
+
+ return;
+ }
+
+ if ( warnMessages == null )
+ {
+ warnMessages = new HashMap<String, Set<String>>();
+ }
+
+ Set<String> set = warnMessages.get( key );
+ if ( set == null )
+ {
+ set = new TreeSet<String>();
+ }
+ set.add( log );
+ warnMessages.put( key, set );
+ }
+
+ /**
+ * @since 1.1.1
+ */
+ private void logWarnings()
+ {
+ if ( getLog().isWarnEnabled() && this.warnMessages != null && !isSecondParsing() )
+ {
+ for ( Map.Entry<String, Set<String>> entry : this.warnMessages.entrySet() )
+ {
+ for ( String msg : entry.getValue() )
+ {
+ getLog().warn( msg );
+ }
+ }
+
+ this.warnMessages = null;
+ }
+ }
+}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java b/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java
index c13fa1a..b2424fe 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/parser/XhtmlBaseParser.java
@@ -77,9 +77,6 @@
/** Used to wrap the definedTerm with its definition, even when one is omitted */
boolean hasDefinitionListItem = false;
- /** Decoration properties, eg for texts. */
- private final SinkEventAttributeSet decoration = new SinkEventAttributeSet();
-
/** Map of warn messages with a String as key to describe the error type and a Set as value.
* Using to reduce warn messages. */
private Map<String, Set<String>> warnMessages;
@@ -432,21 +429,25 @@
}
else if ( parser.getName().equals( HtmlMarkup.U.toString() ) )
{
- decoration.addAttribute( SinkEventAttributes.DECORATION, "underline" );
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.ANNOTATION );
+ sink.inline( attribs );
}
else if ( parser.getName().equals( HtmlMarkup.S.toString() )
|| parser.getName().equals( HtmlMarkup.STRIKE.toString() )
|| parser.getName().equals( "del" ) )
{
- decoration.addAttribute( SinkEventAttributes.DECORATION, "line-through" );
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.LINE_THROUGH );
+ sink.inline( attribs );
}
else if ( parser.getName().equals( HtmlMarkup.SUB.toString() ) )
{
- decoration.addAttribute( SinkEventAttributes.VALIGN, "sub" );
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.SUBSCRIPT );
+ sink.inline( attribs );
}
else if ( parser.getName().equals( HtmlMarkup.SUP.toString() ) )
{
- decoration.addAttribute( SinkEventAttributes.VALIGN, "sup" );
+ attribs.addAttributes( SinkEventAttributeSet.Semantics.SUPERSCRIPT );
+ sink.inline( attribs );
}
else if ( parser.getName().equals( HtmlMarkup.P.toString() ) )
{
@@ -498,7 +499,7 @@
else if ( ( parser.getName().equals( HtmlMarkup.B.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.STRONG.toString() ) ) )
{
- sink.bold();
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
}
else if ( ( parser.getName().equals( HtmlMarkup.I.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.EM.toString() ) ) )
@@ -509,7 +510,7 @@
|| ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.TT.toString() ) ) )
{
- sink.monospaced();
+ sink.inline( SinkEventAttributeSet.Semantics.MONOSPACED );
}
else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
{
@@ -589,12 +590,12 @@
|| parser.getName().equals( HtmlMarkup.STRIKE.toString() )
|| parser.getName().equals( "del" ) )
{
- decoration.removeAttribute( SinkEventAttributes.DECORATION );
+ sink.inline_();
}
else if ( parser.getName().equals( HtmlMarkup.SUB.toString() )
|| parser.getName().equals( HtmlMarkup.SUP.toString() ) )
{
- decoration.removeAttribute( SinkEventAttributes.VALIGN );
+ sink.inline_();
}
else if ( parser.getName().equals( HtmlMarkup.DIV.toString() ) )
{
@@ -649,7 +650,7 @@
else if ( ( parser.getName().equals( HtmlMarkup.B.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.STRONG.toString() ) ) )
{
- sink.bold_();
+ sink.inline_();
}
else if ( ( parser.getName().equals( HtmlMarkup.I.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.EM.toString() ) ) )
@@ -660,7 +661,7 @@
|| ( parser.getName().equals( HtmlMarkup.SAMP.toString() ) )
|| ( parser.getName().equals( HtmlMarkup.TT.toString() ) ) )
{
- sink.monospaced_();
+ sink.inline_();
}
else if ( parser.getName().equals( HtmlMarkup.A.toString() ) )
{
@@ -780,7 +781,7 @@
*/
if ( StringUtils.isNotEmpty( text ) && !isScriptBlock() )
{
- sink.text( text, decoration );
+ sink.text( text );
}
}
@@ -1024,10 +1025,6 @@
this.sectionLevel = 0;
this.inVerbatim = false;
this.inFigure = false;
- while ( this.decoration.getAttributeNames().hasMoreElements() )
- {
- this.decoration.removeAttribute( this.decoration.getAttributeNames().nextElement() );
- }
this.warnMessages = null;
}
@@ -1117,7 +1114,7 @@
}
else
{
- sink.italic_();
+ sink.inline_();
}
}
@@ -1129,7 +1126,7 @@
}
else
{
- sink.italic();
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
}
}
@@ -1222,7 +1219,6 @@
private void handlePreStart( SinkEventAttributeSet attribs, Sink sink )
{
verbatim();
- attribs.removeAttribute( SinkEventAttributes.DECORATION );
sink.verbatim( attribs );
}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/RandomAccessSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/RandomAccessSink.java
index 5b912a4..4a873d4 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/RandomAccessSink.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/RandomAccessSink.java
@@ -96,6 +96,24 @@
this.coreSink = this.currentSink;
}
+ @Override
+ public void address()
+ {
+ currentSink.address();
+ }
+
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ currentSink.address( attributes );
+ }
+
+ @Override
+ public void address_()
+ {
+ currentSink.address_();
+ }
+
/**
* By calling this method a sink reference is added at the current position. You can write to both the new sink
* reference and the original sink. After flushing all sinks will be flushed in the right order.
@@ -152,6 +170,24 @@
}
@Override
+ public void article()
+ {
+ currentSink.article();
+ }
+
+ @Override
+ public void article( SinkEventAttributes attributes )
+ {
+ currentSink.article( attributes );
+ }
+
+ @Override
+ public void article_()
+ {
+ currentSink.article_();
+ }
+
+ @Override
public void author()
{
currentSink.author();
@@ -170,6 +206,24 @@
}
@Override
+ public void blockquote()
+ {
+ currentSink.blockquote();
+ }
+
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ currentSink.blockquote( attributes );
+ }
+
+ @Override
+ public void blockquote_()
+ {
+ currentSink.blockquote_();
+ }
+
+ @Override
public void body()
{
currentSink.body();
@@ -219,6 +273,42 @@
}
@Override
+ public void content()
+ {
+ currentSink.content();
+ }
+
+ @Override
+ public void content( SinkEventAttributes attributes )
+ {
+ currentSink.content( attributes );
+ }
+
+ @Override
+ public void content_()
+ {
+ currentSink.content_();
+ }
+
+ @Override
+ public void data( String value )
+ {
+ currentSink.data( value );
+ }
+
+ @Override
+ public void data( String value, SinkEventAttributes attributes )
+ {
+ currentSink.data( value, attributes );
+ }
+
+ @Override
+ public void data_()
+ {
+ currentSink.data_();
+ }
+
+ @Override
public void date()
{
currentSink.date();
@@ -309,6 +399,24 @@
}
@Override
+ public void division()
+ {
+ currentSink.division();
+ }
+
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ currentSink.division( attributes );
+ }
+
+ @Override
+ public void division_()
+ {
+ currentSink.division_();
+ }
+
+ @Override
public void figure()
{
currentSink.figure();
@@ -382,6 +490,24 @@
}
@Override
+ public void footer()
+ {
+ currentSink.footer();
+ }
+
+ @Override
+ public void footer( SinkEventAttributes attributes )
+ {
+ currentSink.footer( attributes );
+ }
+
+ @Override
+ public void footer_()
+ {
+ currentSink.footer_();
+ }
+
+ @Override
public void head()
{
currentSink.head();
@@ -400,6 +526,24 @@
}
@Override
+ public void header()
+ {
+ currentSink.header();
+ }
+
+ @Override
+ public void header( SinkEventAttributes attributes )
+ {
+ currentSink.header( attributes );
+ }
+
+ @Override
+ public void header_()
+ {
+ currentSink.header_();
+ }
+
+ @Override
public void horizontalRule()
{
currentSink.horizontalRule();
@@ -412,6 +556,24 @@
}
@Override
+ public void inline()
+ {
+ currentSink.inline();
+ }
+
+ @Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ currentSink.inline( attributes );
+ }
+
+ @Override
+ public void inline_()
+ {
+ currentSink.inline_();
+ }
+
+ @Override
public void italic()
{
currentSink.italic();
@@ -436,6 +598,18 @@
}
@Override
+ public void lineBreakOpportunity()
+ {
+ currentSink.lineBreakOpportunity();
+ }
+
+ @Override
+ public void lineBreakOpportunity( SinkEventAttributes attributes )
+ {
+ currentSink.lineBreakOpportunity( attributes );
+ }
+
+ @Override
public void link( String name )
{
currentSink.link( name );
@@ -502,6 +676,24 @@
}
@Override
+ public void navigation()
+ {
+ currentSink.navigation();
+ }
+
+ @Override
+ public void navigation( SinkEventAttributes attributes )
+ {
+ currentSink.navigation( attributes );
+ }
+
+ @Override
+ public void navigation_()
+ {
+ currentSink.navigation_();
+ }
+
+ @Override
public void nonBreakingSpace()
{
currentSink.nonBreakingSpace();
@@ -754,6 +946,24 @@
}
@Override
+ public void sidebar()
+ {
+ currentSink.sidebar();
+ }
+
+ @Override
+ public void sidebar( SinkEventAttributes attributes )
+ {
+ currentSink.sidebar( attributes );
+ }
+
+ @Override
+ public void sidebar_()
+ {
+ currentSink.sidebar_();
+ }
+
+ @Override
public void table()
{
currentSink.table();
@@ -880,6 +1090,24 @@
}
@Override
+ public void time( String datetime )
+ {
+ currentSink.time( datetime );
+ }
+
+ @Override
+ public void time( String datetime, SinkEventAttributes attributes )
+ {
+ currentSink.time( datetime, attributes );
+ }
+
+ @Override
+ public void time_()
+ {
+ currentSink.time_();
+ }
+
+ @Override
public void title()
{
currentSink.title();
@@ -926,4 +1154,4 @@
{
currentSink.enableLogging( log );
}
-}
\ No newline at end of file
+}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkAdapter.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkAdapter.java
index 1199aee..b383a60 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkAdapter.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkAdapter.java
@@ -59,6 +59,42 @@
}
@Override
+ public void article()
+ {
+ // nop
+ }
+
+ @Override
+ public void article_()
+ {
+ // nop
+ }
+
+ @Override
+ public void navigation()
+ {
+ // nop
+ }
+
+ @Override
+ public void navigation_()
+ {
+ // nop
+ }
+
+ @Override
+ public void sidebar()
+ {
+ // nop
+ }
+
+ @Override
+ public void sidebar_()
+ {
+ // nop
+ }
+
+ @Override
public void section1()
{
// nop
@@ -383,6 +419,42 @@
}
@Override
+ public void header()
+ {
+ // nop
+ }
+
+ @Override
+ public void header_()
+ {
+ // nop
+ }
+
+ @Override
+ public void content()
+ {
+ // nop
+ }
+
+ @Override
+ public void content_()
+ {
+ // nop
+ }
+
+ @Override
+ public void footer()
+ {
+ // nop
+ }
+
+ @Override
+ public void footer_()
+ {
+ // nop
+ }
+
+ @Override
public void paragraph()
{
// nop
@@ -395,6 +467,66 @@
}
@Override
+ public void data( String value )
+ {
+ // nop
+ }
+
+ @Override
+ public void data_()
+ {
+ // nop
+ }
+
+ @Override
+ public void time( String datetime )
+ {
+ // nop
+ }
+
+ @Override
+ public void time_()
+ {
+ // nop
+ }
+
+ @Override
+ public void address()
+ {
+ // nop
+ }
+
+ @Override
+ public void address_()
+ {
+ // nop
+ }
+
+ @Override
+ public void blockquote()
+ {
+ // nop
+ }
+
+ @Override
+ public void blockquote_()
+ {
+ // nop
+ }
+
+ @Override
+ public void division()
+ {
+ // nop
+ }
+
+ @Override
+ public void division_()
+ {
+ // nop
+ }
+
+ @Override
public void verbatim( boolean boxed )
{
// nop
@@ -521,6 +653,18 @@
}
@Override
+ public void inline()
+ {
+ // nop
+ }
+
+ @Override
+ public void inline_()
+ {
+ // nop
+ }
+
+ @Override
public void italic()
{
// nop
@@ -563,6 +707,12 @@
}
@Override
+ public void lineBreakOpportunity()
+ {
+ // nop
+ }
+
+ @Override
public void nonBreakingSpace()
{
// nop
@@ -628,6 +778,24 @@
}
@Override
+ public void article( SinkEventAttributes attributes )
+ {
+ article();
+ }
+
+ @Override
+ public void navigation( SinkEventAttributes attributes )
+ {
+ navigation();
+ }
+
+ @Override
+ public void sidebar( SinkEventAttributes attributes )
+ {
+ sidebar();
+ }
+
+ @Override
public void section( int level, SinkEventAttributes attributes )
{
if ( level == SECTION_LEVEL_1 )
@@ -728,6 +896,24 @@
}
@Override
+ public void header( SinkEventAttributes attributes )
+ {
+ header();
+ }
+
+ @Override
+ public void content( SinkEventAttributes attributes )
+ {
+ content();
+ }
+
+ @Override
+ public void footer( SinkEventAttributes attributes )
+ {
+ footer();
+ }
+
+ @Override
public void list( SinkEventAttributes attributes )
{
list();
@@ -830,6 +1016,36 @@
}
@Override
+ public void data( String value, SinkEventAttributes attributes )
+ {
+ data( value );
+ }
+
+ @Override
+ public void time( String datetime, SinkEventAttributes attributes )
+ {
+ time( datetime );
+ }
+
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ address();
+ }
+
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ blockquote();
+ }
+
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ division();
+ }
+
+ @Override
public void verbatim( SinkEventAttributes attributes )
{
MutableAttributeSet atts = SinkUtils.filterAttributes( attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES );
@@ -863,12 +1079,24 @@
}
@Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ inline();
+ }
+
+ @Override
public void lineBreak( SinkEventAttributes attributes )
{
lineBreak();
}
@Override
+ public void lineBreakOpportunity( SinkEventAttributes attributes )
+ {
+ lineBreakOpportunity();
+ }
+
+ @Override
public void text( String text, SinkEventAttributes attributes )
{
text( text );
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkEventAttributeSet.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkEventAttributeSet.java
index 218fa28..9374dbd 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkEventAttributeSet.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/SinkEventAttributeSet.java
@@ -416,4 +416,191 @@
return s.toString();
}
+ /**
+ * Attribute sets for the semantic attribute.
+ */
+ public static class Semantics
+ {
+ /**
+ * An unmodifiable attribute set containing only an emphasis attribute.
+ */
+ public static final SinkEventAttributes EMPHASIS;
+
+ /**
+ * An unmodifiable attribute set containing only a strong attribute.
+ */
+ public static final SinkEventAttributes STRONG;
+
+ /**
+ * An unmodifiable attribute set containing only a small attribute.
+ */
+ public static final SinkEventAttributes SMALL;
+
+ /**
+ * An unmodifiable attribute set containing only a line-through attribute.
+ */
+ public static final SinkEventAttributes LINE_THROUGH;
+
+ /**
+ * An unmodifiable attribute set containing only a citation attribute.
+ */
+ public static final SinkEventAttributes CITATION;
+
+ /**
+ * An unmodifiable attribute set containing only a quote attribute.
+ */
+ public static final SinkEventAttributes QUOTE;
+
+ /**
+ * An unmodifiable attribute set containing only a definition attribute.
+ */
+ public static final SinkEventAttributes DEFINITION;
+
+ /**
+ * An unmodifiable attribute set containing only an abbreviation attribute.
+ */
+ public static final SinkEventAttributes ABBREVIATION;
+
+ /**
+ * An unmodifiable attribute set containing only an italic attribute.
+ */
+ public static final SinkEventAttributes ITALIC;
+
+ /**
+ * An unmodifiable attribute set containing only a bold attribute.
+ */
+ public static final SinkEventAttributes BOLD;
+
+ /**
+ * An unmodifiable attribute set containing only a monospaced attribute.
+ */
+ public static final SinkEventAttributes MONOSPACED;
+
+ /**
+ * An unmodifiable attribute set containing only a code attribute.
+ */
+ public static final SinkEventAttributes CODE;
+
+ /**
+ * An unmodifiable attribute set containing only a variable attribute.
+ */
+ public static final SinkEventAttributes VARIABLE;
+
+ /**
+ * An unmodifiable attribute set containing only a sample attribute.
+ */
+ public static final SinkEventAttributes SAMPLE;
+
+ /**
+ * An unmodifiable attribute set containing only a keyboard attribute.
+ */
+ public static final SinkEventAttributes KEYBOARD;
+
+ /**
+ * An unmodifiable attribute set containing only a superscript attribute.
+ */
+ public static final SinkEventAttributes SUPERSCRIPT;
+
+ /**
+ * An unmodifiable attribute set containing only a subscript attribute.
+ */
+ public static final SinkEventAttributes SUBSCRIPT;
+
+ /**
+ * An unmodifiable attribute set containing only an annotation attribute.
+ */
+ public static final SinkEventAttributes ANNOTATION;
+
+ /**
+ * An unmodifiable attribute set containing only a highlight attribute.
+ */
+ public static final SinkEventAttributes HIGHLIGHT;
+
+ /**
+ * An unmodifiable attribute set containing only a ruby attribute.
+ */
+ public static final SinkEventAttributes RUBY;
+
+ /**
+ * An unmodifiable attribute set containing only a rubyBase attribute.
+ */
+ public static final SinkEventAttributes RUBY_BASE;
+
+ /**
+ * An unmodifiable attribute set containing only a rubyText attribute.
+ */
+ public static final SinkEventAttributes RUBY_TEXT;
+
+ /**
+ * An unmodifiable attribute set containing only a rubyTextContainer attribute.
+ */
+ public static final SinkEventAttributes RUBY_TEXT_CONTAINER;
+
+ /**
+ * An unmodifiable attribute set containing only a rubyParentheses attribute.
+ */
+ public static final SinkEventAttributes RUBY_PARANTHESES;
+
+ /**
+ * An unmodifiable attribute set containing only a bidirectionalIsolation attribute.
+ */
+ public static final SinkEventAttributes BIDIRECTIONAL_ISOLATION;
+
+ /**
+ * An unmodifiable attribute set containing only a bidirectionalOverride attribute.
+ */
+ public static final SinkEventAttributes BIDIRECTIONAL_OVERRIDE;
+
+ /**
+ * An unmodifiable attribute set containing only a phrase attribute.
+ */
+ public static final SinkEventAttributes PHRASE;
+
+ /**
+ * An unmodifiable attribute set containing only an insert attribute.
+ */
+ public static final SinkEventAttributes INSERT;
+
+ /**
+ * An unmodifiable attribute set containing only a delete attribute.
+ */
+ public static final SinkEventAttributes DELETE;
+
+ static
+ {
+ EMPHASIS = new SinkEventAttributeSet( new String[] {SEMANTICS, "emphasis"} ).unmodifiable();
+ STRONG = new SinkEventAttributeSet( new String[] {SEMANTICS, "strong"} ).unmodifiable();
+ SMALL = new SinkEventAttributeSet( new String[] {SEMANTICS, "small"} ).unmodifiable();
+ LINE_THROUGH = new SinkEventAttributeSet( new String[] {SEMANTICS, "line-through"} ).unmodifiable();
+ CITATION = new SinkEventAttributeSet( new String[] {SEMANTICS, "citation"} ).unmodifiable();
+ QUOTE = new SinkEventAttributeSet( new String[] {SEMANTICS, "quote"} ).unmodifiable();
+ DEFINITION = new SinkEventAttributeSet( new String[] {SEMANTICS, "definition"} ).unmodifiable();
+ ABBREVIATION = new SinkEventAttributeSet( new String[] {SEMANTICS, "abbreviation"} ).unmodifiable();
+ ITALIC = new SinkEventAttributeSet( new String[] {SEMANTICS, "italic"} ).unmodifiable();
+ BOLD = new SinkEventAttributeSet( new String[] {SEMANTICS, "bold"} ).unmodifiable();
+ MONOSPACED = new SinkEventAttributeSet( new String[] {SEMANTICS, "monospaced"} ).unmodifiable();
+ CODE = new SinkEventAttributeSet( new String[] {SEMANTICS, "code"} ).unmodifiable();
+ VARIABLE = new SinkEventAttributeSet( new String[] {SEMANTICS, "variable"} ).unmodifiable();
+ SAMPLE = new SinkEventAttributeSet( new String[] {SEMANTICS, "sample"} ).unmodifiable();
+ KEYBOARD = new SinkEventAttributeSet( new String[] {SEMANTICS, "keyboard"} ).unmodifiable();
+ SUPERSCRIPT = new SinkEventAttributeSet( new String[] {SEMANTICS, "superscript"} ).unmodifiable();
+ SUBSCRIPT = new SinkEventAttributeSet( new String[] {SEMANTICS, "subscript"} ).unmodifiable();
+ ANNOTATION = new SinkEventAttributeSet( new String[] {SEMANTICS, "annotation"} ).unmodifiable();
+ HIGHLIGHT = new SinkEventAttributeSet( new String[] {SEMANTICS, "highlight"} ).unmodifiable();
+ RUBY = new SinkEventAttributeSet( new String[] {SEMANTICS, "ruby"} ).unmodifiable();
+ RUBY_BASE = new SinkEventAttributeSet( new String[] {SEMANTICS, "rubyBase"} ).unmodifiable();
+ RUBY_TEXT = new SinkEventAttributeSet( new String[] {SEMANTICS, "rubyText"} ).unmodifiable();
+ RUBY_TEXT_CONTAINER = new SinkEventAttributeSet( new String[] {SEMANTICS,
+ "rubyTextContainer"} ).unmodifiable();
+ RUBY_PARANTHESES = new SinkEventAttributeSet( new String[] {SEMANTICS,
+ "rubyParentheses"} ).unmodifiable();
+ BIDIRECTIONAL_ISOLATION = new SinkEventAttributeSet( new String[] {SEMANTICS,
+ "bidirectionalIsolation"} ).unmodifiable();
+ BIDIRECTIONAL_OVERRIDE = new SinkEventAttributeSet( new String[] {SEMANTICS,
+ "bidirectionalOverride"} ).unmodifiable();
+ PHRASE = new SinkEventAttributeSet( new String[] {SEMANTICS, "phrase"} ).unmodifiable();
+ INSERT = new SinkEventAttributeSet( new String[] {SEMANTICS, "insert"} ).unmodifiable();
+ DELETE = new SinkEventAttributeSet( new String[] {SEMANTICS, "delete"} ).unmodifiable();
+ }
+ }
}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java
new file mode 100644
index 0000000..4ad403a
--- /dev/null
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSink.java
@@ -0,0 +1,2526 @@
+package org.apache.maven.doxia.sink.impl;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TreeSet;
+
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.html.HTML.Attribute;
+import javax.swing.text.html.HTML.Tag;
+
+import org.apache.maven.doxia.markup.HtmlMarkup;
+import org.apache.maven.doxia.markup.Markup;
+import org.apache.maven.doxia.sink.SinkEventAttributes;
+import org.apache.maven.doxia.util.DoxiaUtils;
+import org.apache.maven.doxia.util.HtmlTools;
+
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
+
+/**
+ * Abstract base xhtml5 sink implementation.
+ */
+public class Xhtml5BaseSink
+ extends AbstractXmlSink
+ implements HtmlMarkup
+{
+ // ----------------------------------------------------------------------
+ // Instance fields
+ // ----------------------------------------------------------------------
+
+ /** The PrintWriter to write the result. */
+ private final PrintWriter writer;
+
+ /** Used to collect text events mainly for the head events. */
+ private StringBuffer textBuffer = new StringBuffer();
+
+ /** An indication on if we're inside a head. */
+ private boolean headFlag;
+
+ /** Keep track of the main and div tags for content events. */
+ protected Stack<Tag> contentStack = new Stack<Tag>();
+
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<Tag>> inlineStack = new Stack<List<Tag>>();
+
+ /** An indication on if we're inside a paragraph flag. */
+ private boolean paragraphFlag;
+
+ /** An indication on if we're in verbatim mode. */
+ private boolean verbatimFlag;
+
+ /** Stack of alignment int[] of table cells. */
+ private final LinkedList<int[]> cellJustifStack;
+
+ /** Stack of justification of table cells. */
+ private final LinkedList<Boolean> isCellJustifStack;
+
+ /** Stack of current table cell. */
+ private final LinkedList<Integer> cellCountStack;
+
+ /** Used to style successive table rows differently. */
+ private boolean evenTableRow = true;
+
+ /** The stack of StringWriter to write the table result temporary, so we could play with the output DOXIA-177. */
+ private final LinkedList<StringWriter> tableContentWriterStack;
+
+ private final LinkedList<StringWriter> tableCaptionWriterStack;
+
+ private final LinkedList<PrettyPrintXMLWriter> tableCaptionXMLWriterStack;
+
+ /** The stack of table caption */
+ private final LinkedList<String> tableCaptionStack;
+
+ /** used to store attributes passed to table(). */
+ protected MutableAttributeSet tableAttributes;
+
+ /** Flag to know if {@link #tableRows(int[], boolean)} is called or not. It is mainly to be backward compatible
+ * with some plugins (like checkstyle) which uses:
+ * <pre>
+ * sink.table();
+ * sink.tableRow();
+ * </pre>
+ * instead of
+ * <pre>
+ * sink.table();
+ * sink.tableRows( justify, true );
+ * sink.tableRow();
+ * </pre>
+ * */
+ protected boolean tableRows = false;
+
+ /** Map of warn messages with a String as key to describe the error type and a Set as value.
+ * Using to reduce warn messages. */
+ private Map<String, Set<String>> warnMessages;
+
+ // ----------------------------------------------------------------------
+ // Constructor
+ // ----------------------------------------------------------------------
+
+ /**
+ * Constructor, initialize the PrintWriter.
+ *
+ * @param out The writer to write the result.
+ */
+ public Xhtml5BaseSink( Writer out )
+ {
+ this.writer = new PrintWriter( out );
+
+ this.cellJustifStack = new LinkedList<int[]>();
+ this.isCellJustifStack = new LinkedList<Boolean>();
+ this.cellCountStack = new LinkedList<Integer>();
+ this.tableContentWriterStack = new LinkedList<StringWriter>();
+ this.tableCaptionWriterStack = new LinkedList<StringWriter>();
+ this.tableCaptionXMLWriterStack = new LinkedList<PrettyPrintXMLWriter>();
+ this.tableCaptionStack = new LinkedList<String>();
+
+ init();
+ }
+
+ // ----------------------------------------------------------------------
+ // Accessor methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * To use mainly when playing with the head events.
+ *
+ * @return the current buffer of text events.
+ */
+ protected StringBuffer getTextBuffer()
+ {
+ return this.textBuffer;
+ }
+
+ /**
+ * <p>Setter for the field <code>headFlag</code>.</p>
+ *
+ * @param headFlag an header flag.
+ */
+ protected void setHeadFlag( boolean headFlag )
+ {
+ this.headFlag = headFlag;
+ }
+
+ /**
+ * <p>isHeadFlag.</p>
+ *
+ * @return the current headFlag.
+ */
+ protected boolean isHeadFlag()
+ {
+ return this.headFlag ;
+ }
+
+ /**
+ * <p>Setter for the field <code>verbatimFlag</code>.</p>
+ *
+ * @param verb a verbatim flag.
+ */
+ protected void setVerbatimFlag( boolean verb )
+ {
+ this.verbatimFlag = verb;
+ }
+
+ /**
+ * <p>isVerbatimFlag.</p>
+ *
+ * @return the current verbatim flag.
+ */
+ protected boolean isVerbatimFlag()
+ {
+ return this.verbatimFlag ;
+ }
+
+ /**
+ * <p>Setter for the field <code>cellJustif</code>.</p>
+ *
+ * @param justif the new cell justification array.
+ */
+ protected void setCellJustif( int[] justif )
+ {
+ this.cellJustifStack.addLast( justif );
+ this.isCellJustifStack.addLast( Boolean.TRUE );
+ }
+
+ /**
+ * <p>Getter for the field <code>cellJustif</code>.</p>
+ *
+ * @return the current cell justification array.
+ */
+ protected int[] getCellJustif()
+ {
+ return this.cellJustifStack.getLast();
+ }
+
+ /**
+ * <p>Setter for the field <code>cellCount</code>.</p>
+ *
+ * @param count the new cell count.
+ */
+ protected void setCellCount( int count )
+ {
+ this.cellCountStack.addLast( count );
+ }
+
+ /**
+ * <p>Getter for the field <code>cellCount</code>.</p>
+ *
+ * @return the current cell count.
+ */
+ protected int getCellCount()
+ {
+ return Integer.parseInt( this.cellCountStack.getLast().toString() );
+ }
+
+ /**
+ * Reset all variables.
+ *
+ * @deprecated since 1.1.2, use {@link #init()} instead of.
+ */
+ protected void resetState()
+ {
+ init();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void init()
+ {
+ super.init();
+
+ resetTextBuffer();
+
+ this.cellJustifStack.clear();
+ this.isCellJustifStack.clear();
+ this.cellCountStack.clear();
+ this.tableContentWriterStack.clear();
+ this.tableCaptionWriterStack.clear();
+ this.tableCaptionXMLWriterStack.clear();
+ this.tableCaptionStack.clear();
+ this.inlineStack.clear();
+
+ this.headFlag = false;
+ this.paragraphFlag = false;
+ this.verbatimFlag = false;
+
+ this.evenTableRow = true;
+ this.tableAttributes = null;
+ this.tableRows = false;
+ this.warnMessages = null;
+ }
+
+ /**
+ * Reset the text buffer.
+ */
+ protected void resetTextBuffer()
+ {
+ this.textBuffer = new StringBuffer();
+ }
+
+ // ----------------------------------------------------------------------
+ // Sections
+ // ----------------------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void article()
+ {
+ article( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void article( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.ARTICLE, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void article_()
+ {
+ writeEndTag( HtmlMarkup.ARTICLE );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void navigation()
+ {
+ navigation( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void navigation( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.NAV, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void navigation_()
+ {
+ writeEndTag( HtmlMarkup.NAV );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void sidebar()
+ {
+ sidebar( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void sidebar( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.ASIDE, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void sidebar_()
+ {
+ writeEndTag( HtmlMarkup.ASIDE );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section( int level, SinkEventAttributes attributes )
+ {
+ onSection( level, attributes );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle( int level, SinkEventAttributes attributes )
+ {
+ onSectionTitle( level, attributes );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle_( int level )
+ {
+ onSectionTitle_( level );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section_( int level )
+ {
+ onSection_( level );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section1()
+ {
+ onSection( SECTION_LEVEL_1, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle1()
+ {
+ onSectionTitle( SECTION_LEVEL_1, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle1_()
+ {
+ onSectionTitle_( SECTION_LEVEL_1 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section1_()
+ {
+ onSection_( SECTION_LEVEL_1 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section2()
+ {
+ onSection( SECTION_LEVEL_2, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle2()
+ {
+ onSectionTitle( SECTION_LEVEL_2, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle2_()
+ {
+ onSectionTitle_( SECTION_LEVEL_2 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section2_()
+ {
+ onSection_( SECTION_LEVEL_2 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section3()
+ {
+ onSection( SECTION_LEVEL_3, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle3()
+ {
+ onSectionTitle( SECTION_LEVEL_3, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle3_()
+ {
+ onSectionTitle_( SECTION_LEVEL_3 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section3_()
+ {
+ onSection_( SECTION_LEVEL_3 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section4()
+ {
+ onSection( SECTION_LEVEL_4, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle4()
+ {
+ onSectionTitle( SECTION_LEVEL_4, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle4_()
+ {
+ onSectionTitle_( SECTION_LEVEL_4 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section4_()
+ {
+ onSection_( SECTION_LEVEL_4 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section5()
+ {
+ onSection( SECTION_LEVEL_5, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle5()
+ {
+ onSectionTitle( SECTION_LEVEL_5, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void sectionTitle5_()
+ {
+ onSectionTitle_( SECTION_LEVEL_5 );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void section5_()
+ {
+ onSection_( SECTION_LEVEL_5 );
+ }
+
+ /**
+ * Starts a section. The default class style is <code>section</code>.
+ *
+ * @param depth The level of the section.
+ * @param attributes some attributes. May be null.
+ * @see javax.swing.text.html.HTML.Tag#SECTION
+ */
+ protected void onSection( int depth, SinkEventAttributes attributes )
+ {
+ if ( depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_5 )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttributes( SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES ) );
+
+ writeStartTag( HtmlMarkup.SECTION, att );
+ }
+ }
+
+ /**
+ * Ends a section.
+ *
+ * @param depth The level of the section.
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ protected void onSection_( int depth )
+ {
+ if ( depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_5 )
+ {
+ writeEndTag( HtmlMarkup.SECTION );
+ }
+ }
+
+ /**
+ * Starts a section title.
+ *
+ * @param depth The level of the section title.
+ * @param attributes some attributes. May be null.
+ * @see javax.swing.text.html.HTML.Tag#H2
+ * @see javax.swing.text.html.HTML.Tag#H3
+ * @see javax.swing.text.html.HTML.Tag#H4
+ * @see javax.swing.text.html.HTML.Tag#H5
+ * @see javax.swing.text.html.HTML.Tag#H6
+ */
+ protected void onSectionTitle( int depth, SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ if ( depth == SECTION_LEVEL_1 )
+ {
+ writeStartTag( HtmlMarkup.H2, atts );
+ }
+ else if ( depth == SECTION_LEVEL_2 )
+ {
+ writeStartTag( HtmlMarkup.H3, atts );
+ }
+ else if ( depth == SECTION_LEVEL_3 )
+ {
+ writeStartTag( HtmlMarkup.H4, atts );
+ }
+ else if ( depth == SECTION_LEVEL_4 )
+ {
+ writeStartTag( HtmlMarkup.H5, atts );
+ }
+ else if ( depth == SECTION_LEVEL_5 )
+ {
+ writeStartTag( HtmlMarkup.H6, atts );
+ }
+ }
+
+ /**
+ * Ends a section title.
+ *
+ * @param depth The level of the section title.
+ * @see javax.swing.text.html.HTML.Tag#H2
+ * @see javax.swing.text.html.HTML.Tag#H3
+ * @see javax.swing.text.html.HTML.Tag#H4
+ * @see javax.swing.text.html.HTML.Tag#H5
+ * @see javax.swing.text.html.HTML.Tag#H6
+ */
+ protected void onSectionTitle_( int depth )
+ {
+ if ( depth == SECTION_LEVEL_1 )
+ {
+ writeEndTag( HtmlMarkup.H2 );
+ }
+ else if ( depth == SECTION_LEVEL_2 )
+ {
+ writeEndTag( HtmlMarkup.H3 );
+ }
+ else if ( depth == SECTION_LEVEL_3 )
+ {
+ writeEndTag( HtmlMarkup.H4 );
+ }
+ else if ( depth == SECTION_LEVEL_4 )
+ {
+ writeEndTag( HtmlMarkup.H5 );
+ }
+ else if ( depth == SECTION_LEVEL_5 )
+ {
+ writeEndTag( HtmlMarkup.H6 );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void header()
+ {
+ header( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void header( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.HEADER, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void header_()
+ {
+ writeEndTag( HtmlMarkup.HEADER );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void content()
+ {
+ content( (SinkEventAttributes) null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void content( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ if ( contentStack.empty() )
+ {
+ writeStartTag( contentStack.push( HtmlMarkup.MAIN ), atts );
+ }
+ else
+ {
+ if ( atts == null )
+ {
+ atts = new SinkEventAttributeSet( 1 );
+ }
+
+ if ( !atts.isDefined( SinkEventAttributes.CLASS ) )
+ {
+ atts.addAttribute( SinkEventAttributes.CLASS, "content" );
+ }
+
+ writeStartTag( contentStack.push( HtmlMarkup.DIV ), atts );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void content_()
+ {
+ try
+ {
+ writeEndTag( contentStack.pop() );
+ }
+ catch ( EmptyStackException ese )
+ {
+ /* do nothing if the stack is empty */
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void footer()
+ {
+ footer( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void footer( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.FOOTER, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void footer_()
+ {
+ writeEndTag( HtmlMarkup.FOOTER );
+ }
+
+ // -----------------------------------------------------------------------
+ //
+ // -----------------------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#UL
+ */
+ @Override
+ public void list()
+ {
+ list( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#UL
+ */
+ @Override
+ public void list( SinkEventAttributes attributes )
+ {
+ if ( paragraphFlag )
+ {
+ // The content of element type "p" must match
+ // "(a|br|span|bdo|object|applet|img|map|iframe|tt|i|b|u|s|strike|big|small|font|basefont|em|strong|
+ // dfn|code|q|samp|kbd|var|cite|abbr|acronym|sub|sup|input|select|textarea|label|button|ins|del|script)".
+ paragraph_();
+ }
+
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.UL, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#UL
+ */
+ @Override
+ public void list_()
+ {
+ writeEndTag( HtmlMarkup.UL );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#LI
+ */
+ @Override
+ public void listItem()
+ {
+ listItem( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#LI
+ */
+ @Override
+ public void listItem( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.LI, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#LI
+ */
+ @Override
+ public void listItem_()
+ {
+ writeEndTag( HtmlMarkup.LI );
+ }
+
+ /**
+ * The default list style depends on the numbering.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#OL
+ */
+ @Override
+ public void numberedList( int numbering )
+ {
+ numberedList( numbering, null );
+ }
+
+ /**
+ * The default list style depends on the numbering.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#OL
+ */
+ @Override
+ public void numberedList( int numbering, SinkEventAttributes attributes )
+ {
+ if ( paragraphFlag )
+ {
+ // The content of element type "p" must match
+ // "(a|br|span|bdo|object|applet|img|map|iframe|tt|i|b|u|s|strike|big|small|font|basefont|em|strong|
+ // dfn|code|q|samp|kbd|var|cite|abbr|acronym|sub|sup|input|select|textarea|label|button|ins|del|script)".
+ paragraph_();
+ }
+
+ String style;
+ switch ( numbering )
+ {
+ case NUMBERING_UPPER_ALPHA:
+ style = "upper-alpha";
+ break;
+ case NUMBERING_LOWER_ALPHA:
+ style = "lower-alpha";
+ break;
+ case NUMBERING_UPPER_ROMAN:
+ style = "upper-roman";
+ break;
+ case NUMBERING_LOWER_ROMAN:
+ style = "lower-roman";
+ break;
+ case NUMBERING_DECIMAL:
+ default:
+ style = "decimal";
+ }
+
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ if ( atts == null )
+ {
+ atts = new SinkEventAttributeSet( 1 );
+ }
+
+ atts.addAttribute( Attribute.STYLE, "list-style-type: " + style );
+
+ writeStartTag( HtmlMarkup.OL, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#OL
+ */
+ @Override
+ public void numberedList_()
+ {
+ writeEndTag( HtmlMarkup.OL );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#LI
+ */
+ @Override
+ public void numberedListItem()
+ {
+ numberedListItem( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#LI
+ */
+ @Override
+ public void numberedListItem( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.LI, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#LI
+ */
+ @Override
+ public void numberedListItem_()
+ {
+ writeEndTag( HtmlMarkup.LI );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DL
+ */
+ @Override
+ public void definitionList()
+ {
+ definitionList( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DL
+ */
+ @Override
+ public void definitionList( SinkEventAttributes attributes )
+ {
+ if ( paragraphFlag )
+ {
+ // The content of element type "p" must match
+ // "(a|br|span|bdo|object|applet|img|map|iframe|tt|i|b|u|s|strike|big|small|font|basefont|em|strong|
+ // dfn|code|q|samp|kbd|var|cite|abbr|acronym|sub|sup|input|select|textarea|label|button|ins|del|script)".
+ paragraph_();
+ }
+
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.DL, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DL
+ */
+ @Override
+ public void definitionList_()
+ {
+ writeEndTag( HtmlMarkup.DL );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DT
+ */
+ @Override
+ public void definedTerm( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.DT, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DT
+ */
+ @Override
+ public void definedTerm()
+ {
+ definedTerm( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DT
+ */
+ @Override
+ public void definedTerm_()
+ {
+ writeEndTag( HtmlMarkup.DT );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DD
+ */
+ @Override
+ public void definition()
+ {
+ definition( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DD
+ */
+ @Override
+ public void definition( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.DD, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DD
+ */
+ @Override
+ public void definition_()
+ {
+ writeEndTag( HtmlMarkup.DD );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void figure()
+ {
+ figure( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void figure( SinkEventAttributes attributes )
+ {
+ writeStartTag( HtmlMarkup.FIGURE, attributes );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void figure_()
+ {
+ writeEndTag( HtmlMarkup.FIGURE );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void figureGraphics( String name )
+ {
+ figureGraphics( name, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void figureGraphics( String src, SinkEventAttributes attributes )
+ {
+ MutableAttributeSet filtered = SinkUtils.filterAttributes( attributes, SinkUtils.SINK_IMG_ATTRIBUTES );
+ if ( filtered != null )
+ {
+ filtered.removeAttribute( Attribute.SRC.toString() );
+ }
+
+ int count = ( attributes == null ? 1 : attributes.getAttributeCount() + 1 );
+
+ MutableAttributeSet atts = new SinkEventAttributeSet( count );
+
+ atts.addAttribute( Attribute.SRC, escapeHTML( src ) );
+ atts.addAttributes( filtered );
+
+ if ( atts.getAttribute( Attribute.ALT.toString() ) == null )
+ {
+ atts.addAttribute( Attribute.ALT.toString(), "" );
+ }
+
+ writeStartTag( HtmlMarkup.IMG, atts, true );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void figureCaption()
+ {
+ figureCaption( null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void figureCaption( SinkEventAttributes attributes )
+ {
+ writeStartTag( HtmlMarkup.FIGCAPTION, attributes );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void figureCaption_()
+ {
+ writeEndTag( HtmlMarkup.FIGCAPTION );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#P
+ */
+ @Override
+ public void paragraph()
+ {
+ paragraph( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#P
+ */
+ @Override
+ public void paragraph( SinkEventAttributes attributes )
+ {
+ paragraphFlag = true;
+
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.P, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#P
+ */
+ @Override
+ public void paragraph_()
+ {
+ if ( paragraphFlag )
+ {
+ writeEndTag( HtmlMarkup.P );
+ paragraphFlag = false;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DATA
+ */
+ @Override
+ public void data( String value )
+ {
+ data( value, null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DATA
+ */
+ @Override
+ public void data( String value, SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ if ( value != null )
+ {
+ att.addAttribute( Attribute.VALUE, value );
+ }
+ att.addAttributes( atts );
+
+ writeStartTag( HtmlMarkup.DATA, att );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DATA
+ */
+ @Override
+ public void data_()
+ {
+ writeEndTag( HtmlMarkup.DATA );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TIME
+ */
+ @Override
+ public void time( String datetime )
+ {
+ time( datetime, null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DATA
+ */
+ @Override
+ public void time( String datetime, SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ if ( datetime != null )
+ {
+ att.addAttribute( "datetime", datetime );
+ }
+ att.addAttributes( atts );
+
+ writeStartTag( HtmlMarkup.TIME, att );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void time_()
+ {
+ writeEndTag( HtmlMarkup.TIME );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#ADDRESS
+ */
+ @Override
+ public void address()
+ {
+ address( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#ADDRESS
+ */
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.ADDRESS, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#ADDRESS
+ */
+ @Override
+ public void address_()
+ {
+ writeEndTag( HtmlMarkup.ADDRESS );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BLOCKQUOTE
+ */
+ @Override
+ public void blockquote()
+ {
+ blockquote( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BLOCKQUOTE
+ */
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.BLOCKQUOTE, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BLOCKQUOTE
+ */
+ @Override
+ public void blockquote_()
+ {
+ writeEndTag( HtmlMarkup.BLOCKQUOTE );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ @Override
+ public void division()
+ {
+ division( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.DIV, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ @Override
+ public void division_()
+ {
+ writeEndTag( HtmlMarkup.DIV );
+ }
+
+ /**
+ * The default class style for boxed is <code>source</code>.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ * @see javax.swing.text.html.HTML.Tag#PRE
+ */
+ @Override
+ public void verbatim( boolean boxed )
+ {
+ if ( boxed )
+ {
+ verbatim( SinkEventAttributeSet.BOXED );
+ }
+ else
+ {
+ verbatim( null );
+ }
+ }
+
+ /**
+ * The default class style for boxed is <code>source</code>.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ * @see javax.swing.text.html.HTML.Tag#PRE
+ */
+ @Override
+ public void verbatim( SinkEventAttributes attributes )
+ {
+ if ( paragraphFlag )
+ {
+ // The content of element type "p" must match
+ // "(a|br|span|bdo|object|applet|img|map|iframe|tt|i|b|u|s|strike|big|small|font|basefont|em|strong|
+ // dfn|code|q|samp|kbd|var|cite|abbr|acronym|sub|sup|input|select|textarea|label|button|ins|del|script)".
+ paragraph_();
+ }
+
+ verbatimFlag = true;
+
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES );
+
+ if ( atts == null )
+ {
+ atts = new SinkEventAttributeSet();
+ }
+
+ boolean boxed = false;
+
+ if ( atts.isDefined( SinkEventAttributes.DECORATION ) )
+ {
+ boxed =
+ "boxed".equals( atts.getAttribute( SinkEventAttributes.DECORATION ).toString() );
+ }
+
+ SinkEventAttributes divAtts = null;
+
+ if ( boxed )
+ {
+ divAtts = new SinkEventAttributeSet( new String[] { Attribute.CLASS.toString(), "source" } );
+ }
+
+ atts.removeAttribute( SinkEventAttributes.DECORATION );
+
+ writeStartTag( HtmlMarkup.DIV, divAtts );
+ writeStartTag( HtmlMarkup.PRE, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ * @see javax.swing.text.html.HTML.Tag#PRE
+ */
+ @Override
+ public void verbatim_()
+ {
+ writeEndTag( HtmlMarkup.PRE );
+ writeEndTag( HtmlMarkup.DIV );
+
+ verbatimFlag = false;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#HR
+ */
+ @Override
+ public void horizontalRule()
+ {
+ horizontalRule( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#HR
+ */
+ @Override
+ public void horizontalRule( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_HR_ATTRIBUTES );
+
+ writeSimpleTag( HtmlMarkup.HR, atts );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void table()
+ {
+ // start table with tableRows
+ table( null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void table( SinkEventAttributes attributes )
+ {
+ this.tableContentWriterStack.addLast( new StringWriter() );
+ this.tableRows = false;
+
+ if ( paragraphFlag )
+ {
+ // The content of element type "p" must match
+ // "(a|br|span|bdo|object|applet|img|map|iframe|tt|i|b|u|s|strike|big|small|font|basefont|em|strong|
+ // dfn|code|q|samp|kbd|var|cite|abbr|acronym|sub|sup|input|select|textarea|label|button|ins|del|script)".
+ paragraph_();
+ }
+
+ // start table with tableRows
+ if ( attributes == null )
+ {
+ this.tableAttributes = new SinkEventAttributeSet( 0 );
+ }
+ else
+ {
+ this.tableAttributes = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_TABLE_ATTRIBUTES );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TABLE
+ */
+ @Override
+ public void table_()
+ {
+ this.tableRows = false;
+
+ writeEndTag( HtmlMarkup.TABLE );
+
+ if ( !this.cellCountStack.isEmpty() )
+ {
+ this.cellCountStack.removeLast().toString();
+ }
+
+ if ( this.tableContentWriterStack.isEmpty() )
+ {
+ if ( getLog().isWarnEnabled() )
+ {
+ getLog().warn( "No table content." );
+ }
+ return;
+ }
+
+ String tableContent = this.tableContentWriterStack.removeLast().toString();
+
+ String tableCaption = null;
+ if ( !this.tableCaptionStack.isEmpty() && this.tableCaptionStack.getLast() != null )
+ {
+ tableCaption = this.tableCaptionStack.removeLast().toString();
+ }
+
+ if ( tableCaption != null )
+ {
+ // DOXIA-177
+ StringBuilder sb = new StringBuilder();
+ sb.append( tableContent.substring( 0, tableContent.indexOf( Markup.GREATER_THAN ) + 1 ) );
+ sb.append( tableCaption );
+ sb.append( tableContent.substring( tableContent.indexOf( Markup.GREATER_THAN ) + 1 ) );
+
+ write( sb.toString() );
+ }
+ else
+ {
+ write( tableContent );
+ }
+ }
+
+ /**
+ * The default class style is <code>bodyTable</code>.
+ * The default align is <code>center</code>.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TABLE
+ */
+ @Override
+ public void tableRows( int[] justification, boolean grid )
+ {
+ this.tableRows = true;
+
+ setCellJustif( justification );
+
+ if ( this.tableAttributes == null )
+ {
+ this.tableAttributes = new SinkEventAttributeSet( 0 );
+ }
+
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ if ( !this.tableAttributes.isDefined( Attribute.BORDER.toString() ) )
+ {
+ att.addAttribute( Attribute.BORDER, ( grid ? "1" : "0" ) );
+ }
+
+ if ( !this.tableAttributes.isDefined( Attribute.CLASS.toString() ) )
+ {
+ att.addAttribute( Attribute.CLASS, "bodyTable" );
+ }
+
+ att.addAttributes( this.tableAttributes );
+ this.tableAttributes.removeAttributes( this.tableAttributes );
+
+ writeStartTag( HtmlMarkup.TABLE, att );
+
+ this.cellCountStack.addLast( Integer.valueOf( 0 ) );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableRows_()
+ {
+ this.tableRows = false;
+ if ( !this.cellJustifStack.isEmpty() )
+ {
+ this.cellJustifStack.removeLast();
+ }
+ if ( !this.isCellJustifStack.isEmpty() )
+ {
+ this.isCellJustifStack.removeLast();
+ }
+
+ this.evenTableRow = true;
+ }
+
+ /**
+ * The default class style is <code>a</code> or <code>b</code> depending the row id.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TR
+ */
+ @Override
+ public void tableRow()
+ {
+ // To be backward compatible
+ if ( !this.tableRows )
+ {
+ tableRows( null, false );
+ }
+ tableRow( null );
+ }
+
+ /**
+ * The default class style is <code>a</code> or <code>b</code> depending the row id.
+ *
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TR
+ */
+ @Override
+ public void tableRow( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+
+ if ( evenTableRow )
+ {
+ att.addAttribute( Attribute.CLASS, "a" );
+ }
+ else
+ {
+ att.addAttribute( Attribute.CLASS, "b" );
+ }
+
+ att.addAttributes( SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_TR_ATTRIBUTES ) );
+
+ writeStartTag( HtmlMarkup.TR, att );
+
+ evenTableRow = !evenTableRow;
+
+ if ( !this.cellCountStack.isEmpty() )
+ {
+ this.cellCountStack.removeLast();
+ this.cellCountStack.addLast( Integer.valueOf( 0 ) );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TR
+ */
+ @Override
+ public void tableRow_()
+ {
+ writeEndTag( HtmlMarkup.TR );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableCell()
+ {
+ tableCell( (SinkEventAttributeSet) null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableHeaderCell()
+ {
+ tableHeaderCell( (SinkEventAttributeSet) null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableCell( String width )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttribute( Attribute.WIDTH, width );
+
+ tableCell( false, att );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableHeaderCell( String width )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttribute( Attribute.WIDTH, width );
+
+ tableCell( true, att );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableCell( SinkEventAttributes attributes )
+ {
+ tableCell( false, attributes );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableHeaderCell( SinkEventAttributes attributes )
+ {
+ tableCell( true, attributes );
+ }
+
+ /**
+ * @param headerRow true if it is an header row
+ * @param attributes the cell attributes
+ * @see javax.swing.text.html.HTML.Tag#TH
+ * @see javax.swing.text.html.HTML.Tag#TD
+ */
+ private void tableCell( boolean headerRow, MutableAttributeSet attributes )
+ {
+ Tag t = ( headerRow ? HtmlMarkup.TH : HtmlMarkup.TD );
+
+ if ( attributes == null )
+ {
+ writeStartTag( t, null );
+ }
+ else
+ {
+ writeStartTag( t,
+ SinkUtils.filterAttributes( attributes, SinkUtils.SINK_TD_ATTRIBUTES ) );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableCell_()
+ {
+ tableCell_( false );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void tableHeaderCell_()
+ {
+ tableCell_( true );
+ }
+
+ /**
+ * Ends a table cell.
+ *
+ * @param headerRow true if it is an header row
+ * @see javax.swing.text.html.HTML.Tag#TH
+ * @see javax.swing.text.html.HTML.Tag#TD
+ */
+ private void tableCell_( boolean headerRow )
+ {
+ Tag t = ( headerRow ? HtmlMarkup.TH : HtmlMarkup.TD );
+
+ writeEndTag( t );
+
+ if ( !this.isCellJustifStack.isEmpty() && this.isCellJustifStack.getLast().equals( Boolean.TRUE )
+ && !this.cellCountStack.isEmpty() )
+ {
+ int cellCount = Integer.parseInt( this.cellCountStack.removeLast().toString() );
+ this.cellCountStack.addLast( Integer.valueOf( ++cellCount ) );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#CAPTION
+ */
+ @Override
+ public void tableCaption()
+ {
+ tableCaption( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#CAPTION
+ */
+ @Override
+ public void tableCaption( SinkEventAttributes attributes )
+ {
+ StringWriter sw = new StringWriter();
+ this.tableCaptionWriterStack.addLast( sw );
+ this.tableCaptionXMLWriterStack.addLast( new PrettyPrintXMLWriter( sw ) );
+
+ // TODO: tableCaption should be written before tableRows (DOXIA-177)
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.CAPTION, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#CAPTION
+ */
+ @Override
+ public void tableCaption_()
+ {
+ writeEndTag( HtmlMarkup.CAPTION );
+
+ if ( !this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null )
+ {
+ this.tableCaptionStack.addLast( this.tableCaptionWriterStack.removeLast().toString() );
+ this.tableCaptionXMLWriterStack.removeLast();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#A
+ */
+ @Override
+ public void anchor( String name )
+ {
+ anchor( name, null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#A
+ */
+ @Override
+ public void anchor( String name, SinkEventAttributes attributes )
+ {
+ if ( name == null )
+ {
+ throw new NullPointerException( "Anchor name cannot be null!" );
+ }
+
+ if ( headFlag )
+ {
+ return;
+ }
+
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES );
+
+ String id = name;
+
+ if ( !DoxiaUtils.isValidId( id ) )
+ {
+ id = DoxiaUtils.encodeId( name, true );
+
+ String msg = "Modified invalid anchor name: '" + name + "' to '" + id + "'";
+ logMessage( "modifiedLink", msg );
+ }
+
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttribute( Attribute.NAME, id );
+ att.addAttributes( atts );
+
+ writeStartTag( HtmlMarkup.A, att );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#A
+ */
+ @Override
+ public void anchor_()
+ {
+ if ( !headFlag )
+ {
+ writeEndTag( HtmlMarkup.A );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void link( String name )
+ {
+ link( name, null );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void link( String name, SinkEventAttributes attributes )
+ {
+ if ( attributes == null )
+ {
+ link( name, null, null );
+ }
+ else
+ {
+ String target = (String) attributes.getAttribute( Attribute.TARGET.toString() );
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_LINK_ATTRIBUTES );
+
+ link( name, target, atts );
+ }
+ }
+
+ /**
+ * Adds a link with an optional target.
+ * The default style class for external link is <code>externalLink</code>.
+ *
+ * @param href the link href.
+ * @param target the link target, may be null.
+ * @param attributes an AttributeSet, may be null.
+ * This is supposed to be filtered already.
+ * @see javax.swing.text.html.HTML.Tag#A
+ */
+ private void link( String href, String target, MutableAttributeSet attributes )
+ {
+ if ( href == null )
+ {
+ throw new NullPointerException( "Link name cannot be null!" );
+ }
+
+ if ( headFlag )
+ {
+ return;
+ }
+
+ MutableAttributeSet att = new SinkEventAttributeSet();
+
+ if ( DoxiaUtils.isExternalLink( href ) )
+ {
+ att.addAttribute( Attribute.CLASS, "externalLink" );
+ }
+
+ att.addAttribute( Attribute.HREF, HtmlTools.escapeHTML( href ) );
+
+ if ( target != null )
+ {
+ att.addAttribute( Attribute.TARGET, target );
+ }
+
+ if ( attributes != null )
+ {
+ attributes.removeAttribute( Attribute.HREF.toString() );
+ attributes.removeAttribute( Attribute.TARGET.toString() );
+ att.addAttributes( attributes );
+ }
+
+ writeStartTag( HtmlMarkup.A, att );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#A
+ */
+ @Override
+ public void link_()
+ {
+ if ( !headFlag )
+ {
+ writeEndTag( HtmlMarkup.A );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void inline()
+ {
+ inline( null );
+ }
+
+ private void inlineSemantics( SinkEventAttributes attributes, String semantic,
+ List<Tag> tags, Tag tag )
+ {
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, semantic ) )
+ {
+ writeStartTag( tag );
+ tags.add( 0, tag );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ if ( !headFlag )
+ {
+ List<Tag> tags = new ArrayList<Tag>();
+
+ if ( attributes != null )
+ {
+ inlineSemantics( attributes, "emphasis", tags, HtmlMarkup.EM );
+ inlineSemantics( attributes, "strong", tags, HtmlMarkup.STRONG );
+ inlineSemantics( attributes, "small", tags, HtmlMarkup.SMALL );
+ inlineSemantics( attributes, "line-through", tags, HtmlMarkup.S );
+ inlineSemantics( attributes, "citation", tags, HtmlMarkup.CITE );
+ inlineSemantics( attributes, "quote", tags, HtmlMarkup.Q );
+ inlineSemantics( attributes, "definition", tags, HtmlMarkup.DFN );
+ inlineSemantics( attributes, "abbreviation", tags, HtmlMarkup.ABBR );
+ inlineSemantics( attributes, "italic", tags, HtmlMarkup.I );
+ inlineSemantics( attributes, "bold", tags, HtmlMarkup.B );
+ inlineSemantics( attributes, "code", tags, HtmlMarkup.CODE );
+ inlineSemantics( attributes, "variable", tags, HtmlMarkup.VAR );
+ inlineSemantics( attributes, "sample", tags, HtmlMarkup.SAMP );
+ inlineSemantics( attributes, "keyboard", tags, HtmlMarkup.KBD );
+ inlineSemantics( attributes, "superscript", tags, HtmlMarkup.SUP );
+ inlineSemantics( attributes, "subscript", tags, HtmlMarkup.SUB );
+ inlineSemantics( attributes, "annotation", tags, HtmlMarkup.U );
+ inlineSemantics( attributes, "highlight", tags, HtmlMarkup.MARK );
+ inlineSemantics( attributes, "ruby", tags, HtmlMarkup.RUBY );
+ inlineSemantics( attributes, "rubyBase", tags, HtmlMarkup.RB );
+ inlineSemantics( attributes, "rubyText", tags, HtmlMarkup.RT );
+ inlineSemantics( attributes, "rubyTextContainer", tags, HtmlMarkup.RTC );
+ inlineSemantics( attributes, "rubyParentheses", tags, HtmlMarkup.RP );
+ inlineSemantics( attributes, "bidirectionalIsolation", tags, HtmlMarkup.BDI );
+ inlineSemantics( attributes, "bidirectionalOverride", tags, HtmlMarkup.BDO );
+ inlineSemantics( attributes, "phrase", tags, HtmlMarkup.SPAN );
+ inlineSemantics( attributes, "insert", tags, HtmlMarkup.INS );
+ inlineSemantics( attributes, "delete", tags, HtmlMarkup.DEL );
+ }
+
+ inlineStack.push( tags );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void inline_()
+ {
+ if ( !headFlag )
+ {
+ for ( Tag tag: inlineStack.pop() )
+ {
+ writeEndTag( tag );
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#I
+ */
+ @Override
+ public void italic()
+ {
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#I
+ */
+ @Override
+ public void italic_()
+ {
+ inline_();
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#B
+ */
+ @Override
+ public void bold()
+ {
+ inline( SinkEventAttributeSet.Semantics.BOLD );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#B
+ */
+ @Override
+ public void bold_()
+ {
+ inline_();
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#CODE
+ */
+ @Override
+ public void monospaced()
+ {
+ inline( SinkEventAttributeSet.Semantics.CODE );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#CODE
+ */
+ @Override
+ public void monospaced_()
+ {
+ inline_();
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BR
+ */
+ @Override
+ public void lineBreak()
+ {
+ lineBreak( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BR
+ */
+ @Override
+ public void lineBreak( SinkEventAttributes attributes )
+ {
+ if ( headFlag || isVerbatimFlag() )
+ {
+ getTextBuffer().append( EOL );
+ }
+ else
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BR_ATTRIBUTES );
+
+ writeSimpleTag( HtmlMarkup.BR, atts );
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#WBR
+ */
+ @Override
+ public void lineBreakOpportunity()
+ {
+ lineBreakOpportunity( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#WBR
+ */
+ @Override
+ public void lineBreakOpportunity( SinkEventAttributes attributes )
+ {
+ if ( !headFlag && !isVerbatimFlag() )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BR_ATTRIBUTES );
+
+ writeSimpleTag( HtmlMarkup.WBR, atts );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void pageBreak()
+ {
+ comment( " PB " );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void nonBreakingSpace()
+ {
+ if ( headFlag )
+ {
+ getTextBuffer().append( ' ' );
+ }
+ else
+ {
+ write( " " );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void text( String text )
+ {
+ if ( headFlag )
+ {
+ getTextBuffer().append( text );
+ }
+ else if ( verbatimFlag )
+ {
+ verbatimContent( text );
+ }
+ else
+ {
+ content( text );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void text( String text, SinkEventAttributes attributes )
+ {
+ text( text );
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void rawText( String text )
+ {
+ if ( headFlag )
+ {
+ getTextBuffer().append( text );
+ }
+ else
+ {
+ write( text );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void comment( String comment )
+ {
+ if ( comment != null )
+ {
+ final String originalComment = comment;
+
+ // http://www.w3.org/TR/2000/REC-xml-20001006#sec-comments
+ while ( comment.contains( "--" ) )
+ {
+ comment = comment.replace( "--", "- -" );
+ }
+
+ if ( comment.endsWith( "-" ) )
+ {
+ comment += " ";
+ }
+
+ if ( !originalComment.equals( comment ) )
+ {
+ getLog().warn( "[Xhtml5 Sink] Modified invalid comment '" + originalComment
+ + "' to '" + comment + "'" );
+ }
+
+ final StringBuilder buffer = new StringBuilder( comment.length() + 7 );
+
+ buffer.append( LESS_THAN ).append( BANG ).append( MINUS ).append( MINUS );
+ buffer.append( comment );
+ buffer.append( MINUS ).append( MINUS ).append( GREATER_THAN );
+
+ write( buffer.toString() );
+ }
+ }
+
+ /**
+ * Add an unknown event.
+ * This can be used to generate html tags for which no corresponding sink event exists.
+ *
+ * <p>
+ * If {@link org.apache.maven.doxia.util.HtmlTools#getHtmlTag(String) HtmlTools.getHtmlTag( name )}
+ * does not return null, the corresponding tag will be written.
+ * </p>
+ *
+ * <p>For example, the div block</p>
+ *
+ * <pre>
+ * <div class="detail" style="display:inline">text</div>
+ * </pre>
+ *
+ * <p>can be generated via the following event sequence:</p>
+ *
+ * <pre>
+ * SinkEventAttributeSet atts = new SinkEventAttributeSet();
+ * atts.addAttribute( SinkEventAttributes.CLASS, "detail" );
+ * atts.addAttribute( SinkEventAttributes.STYLE, "display:inline" );
+ * sink.unknown( "div", new Object[]{new Integer( HtmlMarkup.TAG_TYPE_START )}, atts );
+ * sink.text( "text" );
+ * sink.unknown( "div", new Object[]{new Integer( HtmlMarkup.TAG_TYPE_END )}, null );
+ * </pre>
+ *
+ * @param name the name of the event. If this is not a valid xhtml tag name
+ * as defined in {@link org.apache.maven.doxia.markup.HtmlMarkup} then the event is ignored.
+ * @param requiredParams If this is null or the first argument is not an Integer then the event is ignored.
+ * The first argument should indicate the type of the unknown event, its integer value should be one of
+ * {@link org.apache.maven.doxia.markup.HtmlMarkup#TAG_TYPE_START TAG_TYPE_START},
+ * {@link org.apache.maven.doxia.markup.HtmlMarkup#TAG_TYPE_END TAG_TYPE_END},
+ * {@link org.apache.maven.doxia.markup.HtmlMarkup#TAG_TYPE_SIMPLE TAG_TYPE_SIMPLE},
+ * {@link org.apache.maven.doxia.markup.HtmlMarkup#ENTITY_TYPE ENTITY_TYPE}, or
+ * {@link org.apache.maven.doxia.markup.HtmlMarkup#CDATA_TYPE CDATA_TYPE},
+ * otherwise the event will be ignored.
+ * @param attributes a set of attributes for the event. May be null.
+ * The attributes will always be written, no validity check is performed.
+ */
+ @Override
+ public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
+ {
+ if ( requiredParams == null || !( requiredParams[0] instanceof Integer ) )
+ {
+ String msg = "No type information for unknown event: '" + name + "', ignoring!";
+ logMessage( "noTypeInfo", msg );
+
+ return;
+ }
+
+ int tagType = ( (Integer) requiredParams[0] ).intValue();
+
+ if ( tagType == ENTITY_TYPE )
+ {
+ rawText( name );
+
+ return;
+ }
+
+ if ( tagType == CDATA_TYPE )
+ {
+ rawText( EOL + "//<![CDATA[" + requiredParams[1] + "]]>" + EOL );
+
+ return;
+ }
+
+ Tag tag = HtmlTools.getHtmlTag( name );
+
+ if ( tag == null )
+ {
+ String msg = "No HTML tag found for unknown event: '" + name + "', ignoring!";
+ logMessage( "noHtmlTag", msg );
+ }
+ else
+ {
+ if ( tagType == TAG_TYPE_SIMPLE )
+ {
+ writeSimpleTag( tag, escapeAttributeValues( attributes ) );
+ }
+ else if ( tagType == TAG_TYPE_START )
+ {
+ writeStartTag( tag, escapeAttributeValues( attributes ) );
+ }
+ else if ( tagType == TAG_TYPE_END )
+ {
+ writeEndTag( tag );
+ }
+ else
+ {
+ String msg = "No type information for unknown event: '" + name + "', ignoring!";
+ logMessage( "noTypeInfo", msg );
+ }
+ }
+ }
+
+ private SinkEventAttributes escapeAttributeValues( SinkEventAttributes attributes )
+ {
+ SinkEventAttributeSet set = new SinkEventAttributeSet( attributes.getAttributeCount() );
+
+ Enumeration<?> names = attributes.getAttributeNames();
+
+ while ( names.hasMoreElements() )
+ {
+ Object name = names.nextElement();
+
+ set.addAttribute( name, escapeHTML( attributes.getAttribute( name ).toString() ) );
+ }
+
+ return set;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void flush()
+ {
+ writer.flush();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close()
+ {
+ writer.close();
+
+ if ( getLog().isWarnEnabled() && this.warnMessages != null )
+ {
+ for ( Map.Entry<String, Set<String>> entry : this.warnMessages.entrySet() )
+ {
+ for ( String msg : entry.getValue() )
+ {
+ getLog().warn( msg );
+ }
+ }
+
+ this.warnMessages = null;
+ }
+
+ init();
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Write HTML escaped text to output.
+ *
+ * @param text The text to write.
+ */
+ protected void content( String text )
+ {
+ // small hack due to DOXIA-314
+ String txt = escapeHTML( text );
+ txt = StringUtils.replace( txt, "&#", "&#" );
+ write( txt );
+ }
+
+ /**
+ * Write HTML escaped text to output.
+ *
+ * @param text The text to write.
+ */
+ protected void verbatimContent( String text )
+ {
+ write( escapeHTML( text ) );
+ }
+
+ /**
+ * Forward to HtmlTools.escapeHTML( text ).
+ *
+ * @param text the String to escape, may be null
+ * @return the text escaped, "" if null String input
+ * @see org.apache.maven.doxia.util.HtmlTools#escapeHTML(String)
+ */
+ protected static String escapeHTML( String text )
+ {
+ return HtmlTools.escapeHTML( text, false );
+ }
+
+ /**
+ * Forward to HtmlTools.encodeURL( text ).
+ *
+ * @param text the String to encode, may be null.
+ * @return the text encoded, null if null String input.
+ * @see org.apache.maven.doxia.util.HtmlTools#encodeURL(String)
+ */
+ protected static String encodeURL( String text )
+ {
+ return HtmlTools.encodeURL( text );
+ }
+
+ /** {@inheritDoc} */
+ protected void write( String text )
+ {
+ if ( !this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null )
+ {
+ this.tableCaptionXMLWriterStack.getLast().writeText( unifyEOLs( text ) );
+ }
+ else if ( !this.tableContentWriterStack.isEmpty() && this.tableContentWriterStack.getLast() != null )
+ {
+ this.tableContentWriterStack.getLast().write( unifyEOLs( text ) );
+ }
+ else
+ {
+ writer.write( unifyEOLs( text ) );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeStartTag( Tag t, MutableAttributeSet att, boolean isSimpleTag )
+ {
+ if ( this.tableCaptionXMLWriterStack.isEmpty() )
+ {
+ super.writeStartTag ( t, att, isSimpleTag );
+ }
+ else
+ {
+ String tag = ( getNameSpace() != null ? getNameSpace() + ":" : "" ) + t.toString();
+ this.tableCaptionXMLWriterStack.getLast().startElement( tag );
+
+ if ( att != null )
+ {
+ Enumeration<?> names = att.getAttributeNames();
+ while ( names.hasMoreElements() )
+ {
+ Object key = names.nextElement();
+ Object value = att.getAttribute( key );
+
+ this.tableCaptionXMLWriterStack.getLast().addAttribute( key.toString(), value.toString() );
+ }
+ }
+
+ if ( isSimpleTag )
+ {
+ this.tableCaptionXMLWriterStack.getLast().endElement();
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void writeEndTag( Tag t )
+ {
+ if ( this.tableCaptionXMLWriterStack.isEmpty() )
+ {
+ super.writeEndTag( t );
+ }
+ else
+ {
+ this.tableCaptionXMLWriterStack.getLast().endElement();
+ }
+ }
+
+ /**
+ * If debug mode is enabled, log the <code>msg</code> as is, otherwise add unique msg in <code>warnMessages</code>.
+ *
+ * @param key not null
+ * @param msg not null
+ * @see #close()
+ * @since 1.1.1
+ */
+ private void logMessage( String key, String msg )
+ {
+ final String mesg = "[XHTML5 Sink] " + msg;
+ if ( getLog().isDebugEnabled() )
+ {
+ getLog().debug( mesg );
+
+ return;
+ }
+
+ if ( warnMessages == null )
+ {
+ warnMessages = new HashMap<String, Set<String>>();
+ }
+
+ Set<String> set = warnMessages.get( key );
+ if ( set == null )
+ {
+ set = new TreeSet<String>();
+ }
+ set.add( mesg );
+ warnMessages.put( key, set );
+ }
+}
diff --git a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java
index d03dd36..bf6c28a 100644
--- a/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java
+++ b/doxia-core/src/main/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSink.java
@@ -22,11 +22,14 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Stack;
import java.util.TreeSet;
import javax.swing.text.MutableAttributeSet;
@@ -125,6 +128,9 @@
* */
protected boolean tableRows = false;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<Tag>> inlineStack = new Stack<List<Tag>>();
+
/** Map of warn messages with a String as key to describe the error type and a Set as value.
* Using to reduce warn messages. */
private Map<String, Set<String>> warnMessages;
@@ -1009,7 +1015,7 @@
attributes, SinkUtils.SINK_BASE_ATTRIBUTES ) );
paragraph( atts );
- italic();
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
}
@@ -1023,7 +1029,7 @@
}
else
{
- italic_();
+ inline_();
paragraph_();
}
}
@@ -1068,6 +1074,105 @@
}
/**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#ADDRESS
+ */
+ @Override
+ public void address()
+ {
+ address( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#ADDRESS
+ */
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.ADDRESS, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#ADDRESS
+ */
+ @Override
+ public void address_()
+ {
+ writeEndTag( HtmlMarkup.ADDRESS );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BLOCKQUOTE
+ */
+ @Override
+ public void blockquote()
+ {
+ blockquote( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BLOCKQUOTE
+ */
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.BLOCKQUOTE, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BLOCKQUOTE
+ */
+ @Override
+ public void blockquote_()
+ {
+ writeEndTag( HtmlMarkup.BLOCKQUOTE );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ @Override
+ public void division()
+ {
+ division( null );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ writeStartTag( HtmlMarkup.DIV, atts );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ @Override
+ public void division_()
+ {
+ writeEndTag( HtmlMarkup.DIV );
+ }
+
+ /**
* The default class style for boxed is <code>source</code>.
*
* {@inheritDoc}
@@ -1666,6 +1771,74 @@
}
}
+ /** {@inheritDoc} */
+ @Override
+ public void inline()
+ {
+ inline( null );
+ }
+
+ private void inlineSemantics( SinkEventAttributes attributes, String semantic,
+ List<Tag> tags, Tag tag )
+ {
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, semantic ) )
+ {
+ writeStartTag( tag );
+ tags.add( 0, tag );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ if ( !headFlag )
+ {
+ List<Tag> tags = new ArrayList<Tag>();
+
+ if ( attributes != null )
+ {
+ inlineSemantics( attributes, "emphasis", tags, HtmlMarkup.EM );
+ inlineSemantics( attributes, "strong", tags, HtmlMarkup.STRONG );
+ inlineSemantics( attributes, "small", tags, HtmlMarkup.SMALL );
+ inlineSemantics( attributes, "line-through", tags, HtmlMarkup.S );
+ inlineSemantics( attributes, "citation", tags, HtmlMarkup.CITE );
+ inlineSemantics( attributes, "quote", tags, HtmlMarkup.Q );
+ inlineSemantics( attributes, "definition", tags, HtmlMarkup.DFN );
+ inlineSemantics( attributes, "abbreviation", tags, HtmlMarkup.ABBR );
+ inlineSemantics( attributes, "italic", tags, HtmlMarkup.I );
+ inlineSemantics( attributes, "bold", tags, HtmlMarkup.B );
+ inlineSemantics( attributes, "monospaced", tags, HtmlMarkup.TT );
+ inlineSemantics( attributes, "code", tags, HtmlMarkup.CODE );
+ inlineSemantics( attributes, "variable", tags, HtmlMarkup.VAR );
+ inlineSemantics( attributes, "sample", tags, HtmlMarkup.SAMP );
+ inlineSemantics( attributes, "keyboard", tags, HtmlMarkup.KBD );
+ inlineSemantics( attributes, "superscript", tags, HtmlMarkup.SUP );
+ inlineSemantics( attributes, "subscript", tags, HtmlMarkup.SUB );
+ inlineSemantics( attributes, "annotation", tags, HtmlMarkup.U );
+ inlineSemantics( attributes, "bidirectionalOverride", tags, HtmlMarkup.BDO );
+ inlineSemantics( attributes, "phrase", tags, HtmlMarkup.SPAN );
+ inlineSemantics( attributes, "insert", tags, HtmlMarkup.INS );
+ inlineSemantics( attributes, "delete", tags, HtmlMarkup.DEL );
+ }
+
+ inlineStack.push( tags );
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void inline_()
+ {
+ if ( !headFlag )
+ {
+ for ( Tag tag: inlineStack.pop() )
+ {
+ writeEndTag( tag );
+ }
+ }
+ }
+
/**
* {@inheritDoc}
* @see javax.swing.text.html.HTML.Tag#I
@@ -1673,10 +1846,7 @@
@Override
public void italic()
{
- if ( !headFlag )
- {
- writeStartTag( HtmlMarkup.I );
- }
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/**
@@ -1686,10 +1856,7 @@
@Override
public void italic_()
{
- if ( !headFlag )
- {
- writeEndTag( HtmlMarkup.I );
- }
+ inline_();
}
/**
@@ -1699,10 +1866,7 @@
@Override
public void bold()
{
- if ( !headFlag )
- {
- writeStartTag( HtmlMarkup.B );
- }
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/**
@@ -1712,10 +1876,7 @@
@Override
public void bold_()
{
- if ( !headFlag )
- {
- writeEndTag( HtmlMarkup.B );
- }
+ inline_();
}
/**
@@ -1725,10 +1886,7 @@
@Override
public void monospaced()
{
- if ( !headFlag )
- {
- writeStartTag( HtmlMarkup.TT );
- }
+ inline( SinkEventAttributeSet.Semantics.MONOSPACED );
}
/**
@@ -1738,10 +1896,7 @@
@Override
public void monospaced_()
{
- if ( !headFlag )
- {
- writeEndTag( HtmlMarkup.TT );
- }
+ inline_();
}
/**
@@ -1817,48 +1972,7 @@
@Override
public void text( String text, SinkEventAttributes attributes )
{
- if ( attributes == null )
- {
- text( text );
- }
- else
- {
- if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
- {
- writeStartTag( HtmlMarkup.U );
- }
- if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
- {
- writeStartTag( HtmlMarkup.S );
- }
- if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
- {
- writeStartTag( HtmlMarkup.SUB );
- }
- if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
- {
- writeStartTag( HtmlMarkup.SUP );
- }
-
- text( text );
-
- if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
- {
- writeEndTag( HtmlMarkup.SUP );
- }
- if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
- {
- writeEndTag( HtmlMarkup.SUB );
- }
- if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
- {
- writeEndTag( HtmlMarkup.S );
- }
- if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
- {
- writeEndTag( HtmlMarkup.U );
- }
- }
+ text( text );
}
/** {@inheritDoc} */
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java
new file mode 100644
index 0000000..ee1ac18
--- /dev/null
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/parser/Xhtml5BaseParserTest.java
@@ -0,0 +1,857 @@
+package org.apache.maven.doxia.parser;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.Iterator;
+
+import org.apache.maven.doxia.logging.Log;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+import org.apache.maven.doxia.sink.impl.SinkEventElement;
+import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
+
+/**
+ * Test for XhtmlBaseParser.
+ */
+public class Xhtml5BaseParserTest
+ extends AbstractParserTest
+{
+ private Xhtml5BaseParser parser;
+ private final SinkEventTestingSink sink = new SinkEventTestingSink();
+
+
+ @Override
+ protected Parser createParser()
+ {
+ parser = new Xhtml5BaseParser();
+ parser.getLog().setLogLevel( Log.LEVEL_ERROR );
+ return parser;
+ }
+
+ @Override
+ protected String outputExtension()
+ {
+ return "xhtml";
+ }
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ parser = new Xhtml5BaseParser();
+ parser.getLog().setLogLevel( Log.LEVEL_ERROR );
+ sink.reset();
+ }
+
+ /** Test Doxia version. */
+ public void testDoxiaVersion()
+ {
+ assertNotNull( XhtmlBaseParser.doxiaVersion() );
+ assertFalse( "unknown".equals( XhtmlBaseParser.doxiaVersion() ) );
+ }
+
+ /** @throws Exception */
+ public void testHeadingEventsList()
+ throws Exception
+ {
+ String text = "<p><h2></h2><h3></h3><h4></h4><h5></h5><h6></h6><h2></h2></p>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "paragraph", it.next().getName() );
+ assertEquals( "section1", it.next().getName() );
+ assertEquals( "sectionTitle1", it.next().getName() );
+ assertEquals( "sectionTitle1_", it.next().getName() );
+ assertEquals( "section2", it.next().getName() );
+ assertEquals( "sectionTitle2", it.next().getName() );
+ assertEquals( "sectionTitle2_", it.next().getName() );
+ assertEquals( "section3", it.next().getName() );
+ assertEquals( "sectionTitle3", it.next().getName() );
+ assertEquals( "sectionTitle3_", it.next().getName() );
+ assertEquals( "section4", it.next().getName() );
+ assertEquals( "sectionTitle4", it.next().getName() );
+ assertEquals( "sectionTitle4_", it.next().getName() );
+ assertEquals( "section5", it.next().getName() );
+ assertEquals( "sectionTitle5", it.next().getName() );
+ assertEquals( "sectionTitle5_", it.next().getName() );
+ assertEquals( "section5_", it.next().getName() );
+ assertEquals( "section4_", it.next().getName() );
+ assertEquals( "section3_", it.next().getName() );
+ assertEquals( "section2_", it.next().getName() );
+ assertEquals( "section1_", it.next().getName() );
+ assertEquals( "section1", it.next().getName() );
+ assertEquals( "sectionTitle1", it.next().getName() );
+ assertEquals( "sectionTitle1_", it.next().getName() );
+ // this one is missing because we enclose everything in <p> which is not valid xhtml,
+ // needs to be tested in overriding parser, eg XhtmlParser, XdocParser.
+ //assertEquals( "section1_", it.next().getName() );
+ assertEquals( "paragraph_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testNestedHeadingEventsList()
+ throws Exception
+ {
+ // DOXIA-241
+ String text = "<p><h2></h2><h6></h6><h3></h3></p>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "paragraph", it.next().getName() );
+ assertEquals( "section1", it.next().getName() );
+ assertEquals( "sectionTitle1", it.next().getName() );
+ assertEquals( "sectionTitle1_", it.next().getName() );
+
+ assertEquals( "section2", it.next().getName() );
+ assertEquals( "section3", it.next().getName() );
+ assertEquals( "section4", it.next().getName() );
+
+ assertEquals( "section5", it.next().getName() );
+ assertEquals( "sectionTitle5", it.next().getName() );
+ assertEquals( "sectionTitle5_", it.next().getName() );
+ assertEquals( "section5_", it.next().getName() );
+
+ assertEquals( "section4_", it.next().getName() );
+ assertEquals( "section3_", it.next().getName() );
+ assertEquals( "section2_", it.next().getName() );
+
+ assertEquals( "section2", it.next().getName() );
+ assertEquals( "sectionTitle2", it.next().getName() );
+ assertEquals( "sectionTitle2_", it.next().getName() );
+ // these two are missing because we enclose everything in <p> which is not valid xhtml,
+ // needs to be tested in overriding parser, eg XhtmlParser, XdocParser.
+ //assertEquals( "section2_", it.next().getName() );
+ //assertEquals( "section1_", it.next().getName() );
+ assertEquals( "paragraph_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testFigureEventsList()
+ throws Exception
+ {
+ String text = "<img src=\"source\" title=\"caption\" />";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "figureGraphics", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testTableEventsList()
+ throws Exception
+ {
+ // TODO: table caption, see DOXIA-177
+
+ String text = "<table align=\"center\"><tr><th>Header</th></tr><tr><td>cell</td></tr></table>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "table", it.next().getName() );
+ assertEquals( "tableRows", it.next().getName() );
+ assertEquals( "tableRow", it.next().getName() );
+ assertEquals( "tableHeaderCell", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "tableHeaderCell_", it.next().getName() );
+ assertEquals( "tableRow_", it.next().getName() );
+ assertEquals( "tableRow", it.next().getName() );
+ assertEquals( "tableCell", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "tableCell_", it.next().getName() );
+ assertEquals( "tableRow_", it.next().getName() );
+ assertEquals( "tableRows_", it.next().getName() );
+ assertEquals( "table_", it.next().getName() );
+
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testSignificantWhiteSpace()
+ throws Exception
+ {
+ // NOTE significant white space
+ String text = "<p><b>word</b> <i>word</i></p>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "paragraph", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+
+ SinkEventElement el = it.next();
+ assertEquals( "text", el.getName() );
+ assertEquals( " ", (String) el.getArgs()[0] );
+
+ assertEquals( "inline", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "paragraph_", it.next().getName() );
+ assertFalse( it.hasNext() );
+
+
+ // same test with EOL
+ String eol = System.getProperty( "line.separator" );
+ text = "<p><b>word</b>" + eol + "<i>word</i></p>";
+
+ sink.reset();
+ parser.parse( text, sink );
+ it = sink.getEventList().iterator();
+
+ assertEquals( "paragraph", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+
+ el = it.next();
+ assertEquals( "text", el.getName() );
+ // according to section 2.11 of the XML spec, parsers must normalize line breaks to "\n"
+ assertEquals( "\n", (String) el.getArgs()[0] );
+
+ assertEquals( "inline", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "paragraph_", it.next().getName() );
+ assertFalse( it.hasNext() );
+
+
+ // DOXIA-189: there should be no EOL after closing tag
+ text = "<p>There should be no space after the last <i>word</i>.</p>";
+
+ sink.reset();
+ parser.parse( text, sink );
+ it = sink.getEventList().iterator();
+
+ assertEquals( "paragraph", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+
+ el = it.next();
+ assertEquals( "text", el.getName() );
+ assertEquals( ".", (String) el.getArgs()[0] );
+
+ assertEquals( "paragraph_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testPreFormattedText()
+ throws Exception
+ {
+ String text = "<pre><a href=\"what.html\">what</a></pre>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+ assertEquals( "verbatim", it.next().getName() );
+ assertEquals( "link", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "link_", it.next().getName() );
+ assertEquals( "verbatim_", it.next().getName() );
+ assertFalse( it.hasNext() );
+
+ text = "<pre><![CDATA[<a href=\"what.html\">what</a>]]></pre>";
+ sink.reset();
+ parser.parse( text, sink );
+
+ it = sink.getEventList().iterator();
+ assertEquals( "verbatim", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "verbatim_", it.next().getName() );
+ assertFalse( it.hasNext() );
+
+ text = "<pre><![CDATA[<pre>what</pre>]]></pre>";
+ sink.reset();
+ parser.parse( text, sink );
+
+ it = sink.getEventList().iterator();
+ assertEquals( "verbatim", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "verbatim_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testPreEOL()
+ throws Exception
+ {
+ // test EOLs within <pre>: the sink MUST receive a text event for the EOL
+ String text = "<pre><a href=\"what.html\">what</a>" + XhtmlBaseParser.EOL
+ + "<a href=\"what.html\">what</a></pre>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "verbatim", it.next().getName() );
+ assertEquals( "link", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "link_", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "link", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "link_", it.next().getName() );
+ assertEquals( "verbatim_", it.next().getName() );
+ }
+
+ /** @throws Exception */
+ public void testDoxia250()
+ throws Exception
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append( "<!DOCTYPE test [" ).append( XhtmlBaseParser.EOL );
+ sb.append( "<!ENTITY foo \"ř\">" ).append( XhtmlBaseParser.EOL );
+ sb.append( "<!ENTITY foo1 \" \">" ).append( XhtmlBaseParser.EOL );
+ sb.append( "<!ENTITY foo2 \"š\">" ).append( XhtmlBaseParser.EOL );
+ sb.append( "<!ENTITY tritPos \"𝟭\">" ).append( XhtmlBaseParser.EOL );
+ sb.append( "]>" ).append( XhtmlBaseParser.EOL );
+ sb.append( "<p>&foo;&foo1;&foo2;&tritPos;</p>" );
+
+ parser.setValidate( false );
+ parser.parse( sb.toString(), sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ SinkEventElement event = it.next();
+ assertEquals( "paragraph", event.getName() );
+
+ event = it.next();
+ assertEquals( "text", event.getName() );
+ assertEquals( "\u0159", (String) event.getArgs()[0] );
+
+ event = it.next();
+ assertEquals( "text", event.getName() );
+ assertEquals( "\u00A0", (String) event.getArgs()[0] );
+
+ event = it.next();
+ assertEquals( "text", event.getName() );
+ assertEquals( "\u0161", (String) event.getArgs()[0] );
+
+ event = it.next();
+ assertEquals( "text", event.getName() );
+ assertEquals( "\uD835\uDFED", (String) event.getArgs()[0] );
+
+ event = it.next();
+ assertEquals( "paragraph_", event.getName() );
+ }
+
+ /** @throws Exception */
+ public void testEntities()
+ throws Exception
+ {
+ final String text = "<!DOCTYPE test [<!ENTITY flo \"ř\"><!ENTITY tritPos \"𝟭\"><!ENTITY fo \"A\"><!ENTITY myCustom \"&fo;\">]>"
+ + "<body><h2>&&flo;ř&tritPos;𝟭</h2><p>&&flo;ř&tritPos;𝟭&myCustom;</p></body>";
+
+ parser.setValidate( false );
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "section1", it.next().getName() );
+ assertEquals( "sectionTitle1", it.next().getName() );
+
+ SinkEventElement textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "&", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\u0159", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\u0159", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\uD835\uDFED", (String) textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\uD835\uDFED", textEvt.getArgs()[0] );
+
+ assertEquals( "sectionTitle1_", it.next().getName() );
+ assertEquals( "paragraph", it.next().getName() );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "&", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\u0159", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\u0159", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\uD835\uDFED", (String) textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\uD835\uDFED", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "A", textEvt.getArgs()[0] );
+
+ assertEquals( "paragraph_", it.next().getName() );
+// FIXME
+// assertEquals( "section1_", it.next().getName() );
+
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testXhtmlEntities()
+ throws Exception
+ {
+ final String text = "<body><h2>"&</h2><p>'<></p></body>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "section1", it.next().getName() );
+ assertEquals( "sectionTitle1", it.next().getName() );
+
+ SinkEventElement textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\"", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "&", textEvt.getArgs()[0] );
+
+ assertEquals( "sectionTitle1_", it.next().getName() );
+ assertEquals( "paragraph", it.next().getName() );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "\'", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( "<", textEvt.getArgs()[0] );
+
+ textEvt = it.next();
+ assertEquals( "text", textEvt.getName() );
+ assertEquals( ">", textEvt.getArgs()[0] );
+
+ assertEquals( "paragraph_", it.next().getName() );
+
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testLists()
+ throws Exception
+ {
+ String text = "<div><ul><li></li></ul><ol><li></li></ol><dl><dt></dt><dd></dd></dl></div>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "division", it.next().getName() );
+ assertEquals( "list", it.next().getName() );
+ assertEquals( "listItem", it.next().getName() );
+ assertEquals( "listItem_", it.next().getName() );
+ assertEquals( "list_", it.next().getName() );
+
+ assertEquals( "numberedList", it.next().getName() );
+ assertEquals( "numberedListItem", it.next().getName() );
+ assertEquals( "numberedListItem_", it.next().getName() );
+ assertEquals( "numberedList_", it.next().getName() );
+
+ assertEquals( "definitionList", it.next().getName() );
+ assertEquals( "definitionListItem", it.next().getName() );
+ assertEquals( "definedTerm", it.next().getName() );
+ assertEquals( "definedTerm_", it.next().getName() );
+ assertEquals( "definition", it.next().getName() );
+ assertEquals( "definition_", it.next().getName() );
+ assertEquals( "definitionListItem_", it.next().getName() );
+ assertEquals( "definitionList_", it.next().getName() );
+ assertEquals( "division_", it.next().getName() );
+ }
+
+ /** @throws Exception */
+ public void testSimpleTags()
+ throws Exception
+ {
+ String text = "<div><br /><wbr /><hr /><img src=\"img.src\"/></div>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "division", it.next().getName() );
+ assertEquals( "lineBreak", it.next().getName() );
+ assertEquals( "lineBreakOpportunity", it.next().getName() );
+ assertEquals( "horizontalRule", it.next().getName() );
+ assertEquals( "figureGraphics", it.next().getName() );
+ assertEquals( "division_", it.next().getName() );
+ }
+
+ /** @throws Exception */
+ public void testSemanticTags()
+ throws Exception
+ {
+ String text = "<em><strong><small><s><cite><q><dfn><abbr><i><b><code><var><samp><kbd><sup><sub><u><mark><ruby><rb><rt><rtc><rp><bdi><bdo><span><ins><del>a text & Æ</del></ins></span></bdo></bdi></rp></rtc></rt></rb></ruby></mark></u></sub></sup></kbd></samp></var></code></b></i></abbr></dfn></q></cite></s></small></strong></em>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ SinkEventElement event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=emphasis", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=strong", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=small", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=line-through", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=citation", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=quote", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=definition", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=abbreviation", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=italic", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=bold", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=code", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=variable", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=sample", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=keyboard", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=superscript", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=subscript", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=annotation", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=highlight", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=ruby", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=rubyBase", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=rubyText", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=rubyTextContainer", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=rubyParentheses", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=bidirectionalIsolation", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=bidirectionalOverride", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=phrase", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=insert", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=delete", event.getArgs()[0].toString().trim() );
+
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+
+ }
+
+ /** @throws Exception */
+ public void testSpecial()
+ throws Exception
+ {
+ String text = "<p><!-- a pagebreak: --><!-- PB -->  <unknown /></p>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "paragraph", it.next().getName() );
+ assertEquals( "comment", it.next().getName() );
+ assertEquals( "pageBreak", it.next().getName() );
+ assertEquals( "nonBreakingSpace", it.next().getName() );
+ assertEquals( "nonBreakingSpace", it.next().getName() );
+ // unknown events are not reported by the base parser
+ assertEquals( "paragraph_", it.next().getName() );
+ }
+
+ /** @throws Exception */
+ public void testTable()
+ throws Exception
+ {
+ String text = "<table><caption></caption><tr><th></th></tr><tr><td></td></tr></table>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "table", it.next().getName() );
+
+ // DOXIA-374
+ SinkEventElement el = it.next();
+ assertEquals( "tableRows", el.getName() );
+ assertFalse( ( (Boolean) el.getArgs()[1] ).booleanValue() );
+
+ assertEquals( "tableCaption", it.next().getName() );
+ assertEquals( "tableCaption_", it.next().getName() );
+ assertEquals( "tableRow", it.next().getName() );
+ assertEquals( "tableHeaderCell", it.next().getName() );
+ assertEquals( "tableHeaderCell_", it.next().getName() );
+ assertEquals( "tableRow_", it.next().getName() );
+ assertEquals( "tableRow", it.next().getName() );
+ assertEquals( "tableCell", it.next().getName() );
+ assertEquals( "tableCell_", it.next().getName() );
+ assertEquals( "tableRow_", it.next().getName() );
+ assertEquals( "tableRows_", it.next().getName() );
+ assertEquals( "table_", it.next().getName() );
+ }
+
+ /** @throws Exception */
+ public void testFigure()
+ throws Exception
+ {
+ String text = "<figure><img src=\"src.jpg\"/><figcaption></figcaption></figure>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "figure", it.next().getName() );
+ assertEquals( "figureGraphics", it.next().getName() );
+ assertEquals( "figureCaption", it.next().getName() );
+ assertEquals( "figureCaption_", it.next().getName() );
+ assertEquals( "figure_", it.next().getName() );
+ }
+
+ /** @throws Exception */
+ public void testAnchorLink()
+ throws Exception
+ {
+ String text = "<div><a href=\"\"></a>" +
+ "<a href=\"valid\"></a>" +
+ "<a href=\"#1invalid\"></a>" +
+ "<a href=\"http://www.fo.com/index.html#1invalid\"></a>" +
+ "<a name=\"valid\"></a>" +
+ "<a name=\"1invalid\"></a>" +
+ "<a id=\"1invalid\"></a></div>";
+
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ SinkEventElement element = it.next();
+ assertEquals( "division", element.getName() );
+
+ element = it.next();
+ assertEquals( "link", element.getName() );
+ assertEquals( "", element.getArgs()[0] );
+ assertEquals( "link_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "link", element.getName() );
+ assertEquals( "valid", element.getArgs()[0] );
+ assertEquals( "link_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "link", element.getName() );
+ assertEquals( "#a1invalid", element.getArgs()[0] );
+ assertEquals( "link_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "link", element.getName() );
+ assertEquals( "http://www.fo.com/index.html#1invalid", element.getArgs()[0] );
+ assertEquals( "link_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "anchor", element.getName() );
+ assertEquals( "valid", element.getArgs()[0] );
+ assertEquals( "anchor_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "anchor", element.getName() );
+ assertEquals( "a1invalid", element.getArgs()[0] );
+ assertEquals( "anchor_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "anchor", element.getName() );
+ assertEquals( "a1invalid", element.getArgs()[0] );
+ assertEquals( "anchor_", it.next().getName() );
+
+ element = it.next();
+ assertEquals( "division_", element.getName() );
+ }
+
+ /**
+ * Test entities in attributes.
+ *
+ * @throws java.lang.Exception if any.
+ */
+ public void testAttributeEntities()
+ throws Exception
+ {
+ String text = "<script type=\"text/javascript\" src=\"http://ex.com/ex.js?v=l&l=e\"></script>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ SinkEventElement event = it.next();
+
+ assertEquals( "unknown", event.getName() );
+ assertEquals( "script", event.getArgs()[0] );
+ SinkEventAttributeSet attribs = (SinkEventAttributeSet) event.getArgs()[2];
+ // ampersand should be un-escaped
+ assertEquals( "http://ex.com/ex.js?v=l&l=e", attribs.getAttribute( "src" ) );
+ assertEquals( "unknown", it.next().getName() );
+ assertFalse( it.hasNext() );
+
+ sink.reset();
+ text = "<img src=\"http://ex.com/ex.jpg?v=l&l=e\" alt=\"image\"/>";
+ parser.parse( text, sink );
+
+ it = sink.getEventList().iterator();
+ event = it.next();
+ assertEquals( "figureGraphics", event.getName() );
+ attribs = (SinkEventAttributeSet) event.getArgs()[1];
+ // ampersand should be un-escaped
+ assertEquals( "http://ex.com/ex.jpg?v=l&l=e", attribs.getAttribute( "src" ) );
+ }
+
+ public void testUnbalancedDefinitionListItem() throws Exception
+ {
+ String text = "<body><dl><dt>key</dt><dd>value</dd></dl>" +
+ "<dl><dd>value</dd></dl>" +
+ "<dl><dt>key</dt></dl>" +
+ "<dl></dl>" +
+ "<dl><dd>value</dd><dt>key</dt></dl></body>";
+
+ parser.parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+ assertStartsWith( it, "definitionList", "definitionListItem", "definedTerm", "text", "definedTerm_",
+ "definition", "text", "definition_", "definitionListItem_", "definitionList_" );
+ assertStartsWith( it, "definitionList", "definitionListItem", "definition", "text", "definition_",
+ "definitionListItem_", "definitionList_" );
+ assertStartsWith( it, "definitionList", "definitionListItem", "definedTerm", "text", "definedTerm_",
+ "definitionListItem_", "definitionList_" );
+ assertStartsWith( it, "definitionList", "definitionList_" );
+ assertEquals( it, "definitionList", "definitionListItem", "definition", "text", "definition_",
+ "definitionListItem_", "definitionListItem", "definedTerm", "text", "definedTerm_",
+ "definitionListItem_", "definitionList_" );
+ }
+}
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/parser/XhtmlBaseParserTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/parser/XhtmlBaseParserTest.java
index 593194c..45f8a3d 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/parser/XhtmlBaseParserTest.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/parser/XhtmlBaseParserTest.java
@@ -208,17 +208,17 @@
Iterator<SinkEventElement> it = sink.getEventList().iterator();
assertEquals( "paragraph", it.next().getName() );
- assertEquals( "bold", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
assertEquals( "text", it.next().getName() );
- assertEquals( "bold_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
SinkEventElement el = it.next();
assertEquals( "text", el.getName() );
assertEquals( " ", (String) el.getArgs()[0] );
- assertEquals( "italic", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
assertEquals( "text", it.next().getName() );
- assertEquals( "italic_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
assertEquals( "paragraph_", it.next().getName() );
assertFalse( it.hasNext() );
@@ -232,18 +232,18 @@
it = sink.getEventList().iterator();
assertEquals( "paragraph", it.next().getName() );
- assertEquals( "bold", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
assertEquals( "text", it.next().getName() );
- assertEquals( "bold_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
el = it.next();
assertEquals( "text", el.getName() );
// according to section 2.11 of the XML spec, parsers must normalize line breaks to "\n"
assertEquals( "\n", (String) el.getArgs()[0] );
- assertEquals( "italic", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
assertEquals( "text", it.next().getName() );
- assertEquals( "italic_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
assertEquals( "paragraph_", it.next().getName() );
assertFalse( it.hasNext() );
@@ -257,9 +257,9 @@
assertEquals( "paragraph", it.next().getName() );
assertEquals( "text", it.next().getName() );
- assertEquals( "italic", it.next().getName() );
+ assertEquals( "inline", it.next().getName() );
assertEquals( "text", it.next().getName() );
- assertEquals( "italic_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
el = it.next();
assertEquals( "text", el.getName() );
@@ -348,7 +348,7 @@
Iterator<SinkEventElement> it = sink.getEventList().iterator();
SinkEventElement event = it.next();
- assertEquals( "bold", event.getName() );
+ assertEquals( "inline", event.getName() );
event = it.next();
assertEquals( "text", event.getName() );
@@ -367,7 +367,7 @@
assertEquals( "\uD835\uDFED", (String) event.getArgs()[0] );
event = it.next();
- assertEquals( "bold_", event.getName() );
+ assertEquals( "inline_", event.getName() );
}
/** @throws Exception */
@@ -492,41 +492,6 @@
}
/** @throws Exception */
- public void testDecoration()
- throws Exception
- {
- String text = "<div><u>u</u><s>s</s><del>del</del><strike>strike</strike><sub>sub</sub><sup>sup</sup></div>";
- parser.parse( text, sink );
- Iterator<SinkEventElement> it = sink.getEventList().iterator();
-
- SinkEventElement event = it.next();
- assertEquals( "text", event.getName() );
- assertEquals( "u", (String) event.getArgs()[0] );
-
- event = it.next();
- assertEquals( "text", event.getName() );
- assertEquals( "s", (String) event.getArgs()[0] );
-
- event = it.next();
- assertEquals( "text", event.getName() );
- assertEquals( "del", (String) event.getArgs()[0] );
-
- event = it.next();
- assertEquals( "text", event.getName() );
- assertEquals( "strike", (String) event.getArgs()[0] );
-
- event = it.next();
- assertEquals( "text", event.getName() );
- assertEquals( "sub", (String) event.getArgs()[0] );
-
- event = it.next();
- assertEquals( "text", event.getName() );
- assertEquals( "sup", (String) event.getArgs()[0] );
-// assertTrue( ( (SinkEventAttributeSet) event.getArgs()[1] )
-// .containsAttribute( SinkEventAttributeSet.VALIGN, "sup" ) ); // TODO
- }
-
- /** @throws Exception */
public void testLists()
throws Exception
{
@@ -555,32 +520,6 @@
}
/** @throws Exception */
- public void testStyles()
- throws Exception
- {
- String text = "<div><b></b><strong></strong><i></i><em></em><code></code><samp></samp><tt></tt></div>";
- parser.parse( text, sink );
- Iterator<SinkEventElement> it = sink.getEventList().iterator();
-
- assertEquals( "bold", it.next().getName() );
- assertEquals( "bold_", it.next().getName() );
- assertEquals( "bold", it.next().getName() );
- assertEquals( "bold_", it.next().getName() );
-
- assertEquals( "italic", it.next().getName() );
- assertEquals( "italic_", it.next().getName() );
- assertEquals( "italic", it.next().getName() );
- assertEquals( "italic_", it.next().getName() );
-
- assertEquals( "monospaced", it.next().getName() );
- assertEquals( "monospaced_", it.next().getName() );
- assertEquals( "monospaced", it.next().getName() );
- assertEquals( "monospaced_", it.next().getName() );
- assertEquals( "monospaced", it.next().getName() );
- assertEquals( "monospaced_", it.next().getName() );
- }
-
- /** @throws Exception */
public void testSimpleTags()
throws Exception
{
@@ -594,6 +533,62 @@
}
/** @throws Exception */
+ public void testSemanticTags()
+ throws Exception
+ {
+ String text = "<s><i><b><code><samp><sup><sub><u>a text & Æ</u></sub></sup></samp></code></b></i></s>";
+ parser.parse( text, sink );
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ SinkEventElement event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=line-through", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=italic", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=bold", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=monospaced", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=monospaced", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=superscript", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=subscript", event.getArgs()[0].toString().trim() );
+
+ event = it.next();
+ assertEquals( "inline", event.getName() );
+ assertEquals( "semantics=annotation", event.getArgs()[0].toString().trim() );
+
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+ assertEquals( "inline_", it.next().getName() );
+
+ }
+
+ /** @throws Exception */
public void testSpecial()
throws Exception
{
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java
index 11627f0..df84ffe 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/AbstractSinkTest.java
@@ -35,9 +35,6 @@
/**
* Abstract base class to test sinks.
- *
- * @version $Id$
- * @since 1.0
*/
public abstract class AbstractSinkTest
extends AbstractModuleTest
@@ -233,6 +230,60 @@
}
/**
+ * Checks that the sequence <code>[article(), article_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getArticleBlock getArticleBlock()}.
+ */
+ public void testArticle()
+ {
+ sink.article();
+ sink.article_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getArticleBlock();
+
+ assertEquals( "Wrong article!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[navigation(), navigation_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getNavigationBlock getNavigationBlock()}.
+ */
+ public void testNavigation()
+ {
+ sink.navigation();
+ sink.navigation_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getNavigationBlock();
+
+ assertEquals( "Wrong navigation!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[sidebar(), sidebar_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getSidebarBlock getSidebarBlock()}.
+ */
+ public void testSidebar()
+ {
+ sink.sidebar();
+ sink.sidebar_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getSidebarBlock();
+
+ assertEquals( "Wrong sidebar!", expected, actual );
+ }
+
+ /**
* Checks that the sequence <code>[sectionTitle(), text( title ),
* sectionTitle_()]</code>, invoked on the current sink, produces
* the same result as
@@ -263,9 +314,11 @@
{
String title = "Title1";
sink.section1();
+ sink.header();
sink.sectionTitle1();
sink.text( title );
sink.sectionTitle1_();
+ sink.header_();
sink.section1_();
sink.flush();
sink.close();
@@ -286,9 +339,11 @@
{
String title = "Title2";
sink.section2();
+ sink.header();
sink.sectionTitle2();
sink.text( title );
sink.sectionTitle2_();
+ sink.header_();
sink.section2_();
sink.flush();
sink.close();
@@ -309,9 +364,11 @@
{
String title = "Title3";
sink.section3();
+ sink.header();
sink.sectionTitle3();
sink.text( title );
sink.sectionTitle3_();
+ sink.header_();
sink.section3_();
sink.flush();
sink.close();
@@ -333,9 +390,11 @@
{
String title = "Title4";
sink.section4();
+ sink.header();
sink.sectionTitle4();
sink.text( title );
sink.sectionTitle4_();
+ sink.header_();
sink.section4_();
sink.flush();
sink.close();
@@ -356,9 +415,11 @@
{
String title = "Title5";
sink.section5();
+ sink.header();
sink.sectionTitle5();
sink.text( title );
sink.sectionTitle5_();
+ sink.header_();
sink.section5_();
sink.flush();
sink.close();
@@ -370,6 +431,62 @@
}
/**
+ * Checks that the sequence <code>[header(), header_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getHeaderBlock getHeaderBlock()}.
+ */
+ public void testHeader()
+ {
+ sink.header();
+ sink.header_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getHeaderBlock();
+
+ assertEquals( "Wrong header!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[content(), content(), content_(), content_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getContentBlock getContentBlock()}.
+ */
+ public void testContent()
+ {
+ sink.content();
+ sink.content();
+ sink.content_();
+ sink.content_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getContentBlock();
+
+ assertEquals( "Wrong content!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[footer(), footer_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getHeaderBlock getHeaderBlock()}.
+ */
+ public void testFooter()
+ {
+ sink.footer();
+ sink.footer_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getFooterBlock();
+
+ assertEquals( "Wrong footer!", expected, actual );
+ }
+
+ /**
* Checks that the sequence <code>[list(), listItem(), text( item ),
* listItem_(), list_()]</code>, invoked on the current sink, produces
* the same result as {@link #getListBlock getListBlock}( item ).
@@ -564,6 +681,108 @@
}
/**
+ * Checks that the sequence <code>[data(), text( text ),
+ * data_()]</code>, invoked on the current sink, produces
+ * the same result as {@link #getDataBlock getDataBlock}( text ).
+ */
+ public void testData()
+ {
+ String value = "Value";
+ String text = "Text";
+ sink.data( value );
+ sink.text( text );
+ sink.data_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getDataBlock( value, text );
+
+ assertEquals( "Wrong data!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[time(), text( text ),
+ * time_()]</code>, invoked on the current sink, produces
+ * the same result as {@link #getTimeBlock getTimeBlock}( text ).
+ */
+ public void testTime()
+ {
+ String datetime = "DateTime";
+ String text = "Text";
+ sink.time( datetime );
+ sink.text( text );
+ sink.time_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getTimeBlock( datetime, text );
+
+ assertEquals( "Wrong time!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[address(), text( text ),
+ * address_()]</code>, invoked on the current sink, produces
+ * the same result as {@link #getAddressBlock getAddressBlock}( text ).
+ */
+ public void testAddress()
+ {
+ String text = "Text";
+ sink.address();
+ sink.text( text );
+ sink.address_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getAddressBlock( text );
+
+ assertEquals( "Wrong address!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[blockquote(), text( text ),
+ * blockquote_()]</code>, invoked on the current sink, produces
+ * the same result as {@link #getBlackquoteBlock getBlockquoteBlock}( text ).
+ */
+ public void testBlockquote()
+ {
+ String text = "Text";
+ sink.blockquote();
+ sink.text( text );
+ sink.blockquote_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getBlockquoteBlock( text );
+
+ assertEquals( "Wrong blockquote!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[division(), text( text ),
+ * division_()]</code>, invoked on the current sink, produces
+ * the same result as {@link #getDivisionBlock getDivisionBlock}( text ).
+ */
+ public void testDivider()
+ {
+ String text = "Text";
+ sink.division();
+ sink.text( text );
+ sink.division_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getDivisionBlock( text );
+
+ assertEquals( "Wrong division!", expected, actual );
+ }
+
+ /**
* Checks that the sequence <code>[verbatim( SinkEventAttributeSet.BOXED ), text( text ),
* verbatim_()]</code>, invoked on the current sink, produces the
* same result as {@link #getVerbatimBlock getVerbatimBlock}( text ).
@@ -659,63 +878,83 @@
}
/**
- * Checks that the sequence <code>[italic(), text( text ), italic_()]</code>,
+ * Checks that the sequence <code>[inline(), text( text ), inline_()]</code>,
* invoked on the current sink, produces the same result as
- * {@link #getItalicBlock getItalicBlock}( text ).
+ * {@link #getInlineBlock getInlineBlock}( text ).
*/
- public void testItalic()
+ public void testInline()
{
- String text = "Italic";
- sink.italic();
+ String text = "Inline";
+ sink.inline();
sink.text( text );
- sink.italic_();
+ sink.inline_();
sink.flush();
sink.close();
String actual = testWriter.toString();
- String expected = getItalicBlock( text );
+ String expected = getInlineBlock( text );
- assertEquals( "Wrong italic!", expected, actual );
+ assertEquals( "Wrong inline!", expected, actual );
}
/**
- * Checks that the sequence <code>[bold(), text( text ), bold_()]</code>,
+ * Checks that the sequence <code>[inline(bold), text( text ), inline_()]</code>,
* invoked on the current sink, produces the same result as
- * {@link #getBoldBlock getBoldBlock}( text ).
+ * {@link #getInlineBoldBlock getInlineBoldBlock}( text ).
*/
- public void testBold()
+ public void testInlineBold()
{
- String text = "Bold";
- sink.bold();
+ String text = "InlineBold";
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
sink.text( text );
- sink.bold_();
+ sink.inline_();
sink.flush();
sink.close();
String actual = testWriter.toString();
- String expected = getBoldBlock( text );
+ String expected = getInlineBoldBlock( text );
- assertEquals( "Wrong bold!", expected, actual );
+ assertEquals( "Wrong inline bold!", expected, actual );
}
/**
- * Checks that the sequence <code>[monospaced(), text( text ),
- * monospaced_()]</code>, invoked on the current sink, produces the same
- * result as {@link #getMonospacedBlock getMonospacedBlock}( text ).
+ * Checks that the sequence <code>[inline(italic), text( text ), inline_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getInlineBoldBlock getInlineBoldBlock}( text ).
*/
- public void testMonospaced()
+ public void testInlineItalic()
{
- String text = "Monospaced";
- sink.monospaced();
+ String text = "InlineItalic";
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
sink.text( text );
- sink.monospaced_();
+ sink.inline_();
sink.flush();
sink.close();
String actual = testWriter.toString();
- String expected = getMonospacedBlock( text );
+ String expected = getInlineItalicBlock( text );
- assertEquals( "Wrong monospaced!", expected, actual );
+ assertEquals( "Wrong inline italic!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[inline(code), text( text ), inline_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getInlineBoldBlock getInlineBoldBlock}( text ).
+ */
+ public void testInlineCode()
+ {
+ String text = "InlineCode";
+ sink.inline( SinkEventAttributeSet.Semantics.CODE );
+ sink.text( text );
+ sink.inline_();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getInlineCodeBlock( text );
+
+ assertEquals( "Wrong inline code!", expected, actual );
}
/**
@@ -736,6 +975,23 @@
}
/**
+ * Checks that the sequence <code>[lineBreakOpportunity()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getLineBreakOpportunityBlock getLineBreakOpportunityBlock()}.
+ */
+ public void testLineBreakOpportunity()
+ {
+ sink.lineBreakOpportunity();
+ sink.flush();
+ sink.close();
+
+ String actual = testWriter.toString();
+ String expected = getLineBreakOpportunityBlock();
+
+ assertEquals( "Wrong lineBreakOpportunity!", expected, actual );
+ }
+
+ /**
* Checks that the sequence <code>[nonBreakingSpace()]</code>,
* invoked on the current sink, produces the same result as
* {@link #getNonBreakingSpaceBlock getNonBreakingSpaceBlock()}.
@@ -910,6 +1166,27 @@
protected abstract String getBodyBlock();
/**
+ * Returns an article block generated by this sink.
+ * @return The result of invoking an article block on the current sink.
+ * @see #testArticle()
+ */
+ protected abstract String getArticleBlock();
+
+ /**
+ * Returns an navigation block generated by this sink.
+ * @return The result of invoking an navigation block on the current sink.
+ * @see #testNavigation()
+ */
+ protected abstract String getNavigationBlock();
+
+ /**
+ * Returns a sidebar block generated by this sink.
+ * @return The result of invoking an sidebar block on the current sink.
+ * @see #testSidebar()
+ */
+ protected abstract String getSidebarBlock();
+
+ /**
* Returns a SectionTitle block generated by this sink.
* @param title The title to use.
* @return The result of invoking a SectionTitle block on the current sink.
@@ -958,6 +1235,27 @@
protected abstract String getSection5Block( String title );
/**
+ * Returns a header block generated by this sink.
+ * @return The result of invoking a header block on the current sink.
+ * @see #testHeader()
+ */
+ protected abstract String getHeaderBlock();
+
+ /**
+ * Returns a content block generated by this sink.
+ * @return The result of invoking a content block on the current sink.
+ * @see #testContent()
+ */
+ protected abstract String getContentBlock();
+
+ /**
+ * Returns a footer block generated by this sink.
+ * @return The result of invoking a footer block on the current sink.
+ * @see #testFooter()
+ */
+ protected abstract String getFooterBlock();
+
+ /**
* Returns a list block generated by this sink.
* @param item The item to use.
* @return The result of invoking a list block on the current sink.
@@ -1010,6 +1308,48 @@
protected abstract String getParagraphBlock( String text );
/**
+ * Returns a Data block generated by this sink.
+ * @param value The value to use.
+ * @param text The text to use.
+ * @return The result of invoking a Data block on the current sink.
+ * @see #testData()
+ */
+ protected abstract String getDataBlock( String value, String text );
+
+ /**
+ * Returns a Time block generated by this sink.
+ * @param datetime The datetime to use.
+ * @param text The text to use.
+ * @return The result of invoking a Time block on the current sink.
+ * @see #testTime()
+ */
+ protected abstract String getTimeBlock( String datetime, String text );
+
+ /**
+ * Returns an Address block generated by this sink.
+ * @param text The text to use.
+ * @return The result of invoking an Address block on the current sink.
+ * @see #testAddress()
+ */
+ protected abstract String getAddressBlock( String text );
+
+ /**
+ * Returns a Blockquote block generated by this sink.
+ * @param text The text to use.
+ * @return The result of invoking a Blockquote block on the current sink.
+ * @see #testBlockquote()
+ */
+ protected abstract String getBlockquoteBlock( String text );
+
+ /**
+ * Returns a Division block generated by this sink.
+ * @param text The text to use.
+ * @return The result of invoking a Division block on the current sink.
+ * @see #testDivision()
+ */
+ protected abstract String getDivisionBlock( String text );
+
+ /**
* Returns a Verbatim block generated by this sink.
* @param text The text to use.
* @return The result of invoking a Verbatim block on the current sink.
@@ -1049,28 +1389,36 @@
protected abstract String getLinkBlock( String link, String text );
/**
- * Returns a Italic block generated by this sink.
+ * Returns an Inline block generated by this sink.
* @param text The text to use.
- * @return The result of invoking a Italic block on the current sink.
- * @see #testItalic()
+ * @return The result of invoking a Inline block on the current sink.
+ * @see #testInline()
*/
- protected abstract String getItalicBlock( String text );
+ protected abstract String getInlineBlock( String text );
/**
- * Returns a Bold block generated by this sink.
+ * Returns an Inline italic block generated by this sink.
* @param text The text to use.
- * @return The result of invoking a Bold block on the current sink.
- * @see #testBold()
+ * @return The result of invoking a Inline italic block on the current sink.
+ * @see #testInlineItalic()
*/
- protected abstract String getBoldBlock( String text );
+ protected abstract String getInlineItalicBlock( String text );
/**
- * Returns a Monospaced block generated by this sink.
+ * Returns an Inline bold block generated by this sink.
* @param text The text to use.
- * @return The result of invoking a Monospaced block on the current sink.
- * @see #testMonospaced()
+ * @return The result of invoking a Inline bold block on the current sink.
+ * @see #testInlineBold()
*/
- protected abstract String getMonospacedBlock( String text );
+ protected abstract String getInlineBoldBlock( String text );
+
+ /**
+ * Returns an Inline code block generated by this sink.
+ * @param text The text to use.
+ * @return The result of invoking a Inline code block on the current sink.
+ * @see #testInlineBold()
+ */
+ protected abstract String getInlineCodeBlock( String text );
/**
* Returns a LineBreak block generated by this sink.
@@ -1080,6 +1428,14 @@
protected abstract String getLineBreakBlock();
/**
+ * Returns a LineBreakOpportunity block generated by this sink.
+ * @return The result of invoking a LineBreakOpportunity block on the
+ * current sink.
+ * @see #testLineBreakOpportunity()
+ */
+ protected abstract String getLineBreakOpportunityBlock();
+
+ /**
* Returns a NonBreakingSpace block generated by this sink.
* @return The result of invoking a NonBreakingSpace block
* on the current sink.
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkAdapterTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkAdapterTest.java
index 1ec9fca..e2b870e 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkAdapterTest.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkAdapterTest.java
@@ -54,6 +54,36 @@
}
/**
+ * Test of article method, of class SinkAdapter.
+ */
+ public void testArticle()
+ {
+ instance.article();
+ instance.article( null );
+ instance.article_();
+ }
+
+ /**
+ * Test of navigation method, of class SinkAdapter.
+ */
+ public void testNavigation()
+ {
+ instance.navigation();
+ instance.navigation( null );
+ instance.navigation_();
+ }
+
+ /**
+ * Test of sidebar method, of class SinkAdapter.
+ */
+ public void testSidebar()
+ {
+ instance.sidebar();
+ instance.sidebar( null );
+ instance.sidebar_();
+ }
+
+ /**
* Test of section1 method, of class SinkAdapter.
*/
public void testSection1()
@@ -328,6 +358,36 @@
}
/**
+ * Test of header method, of class SinkAdapter.
+ */
+ public void testHeader()
+ {
+ instance.header();
+ instance.header( null );
+ instance.header_();
+ }
+
+ /**
+ * Test of content method, of class SinkAdapter.
+ */
+ public void testContent()
+ {
+ instance.content();
+ instance.content( null );
+ instance.content_();
+ }
+
+ /**
+ * Test of footer method, of class SinkAdapter.
+ */
+ public void testFooter()
+ {
+ instance.footer();
+ instance.footer( null );
+ instance.footer_();
+ }
+
+ /**
* Test of paragraph method, of class SinkAdapter.
*/
public void testParagraph()
@@ -338,6 +398,58 @@
}
/**
+ * Test of data method, of class SinkAdapter.
+ */
+ public void testData()
+ {
+ String value = "";
+ instance.data( value );
+ instance.data( value, null );
+ instance.data_();
+ }
+
+ /**
+ * Test of time method, of class SinkAdapter.
+ */
+ public void testTime()
+ {
+ String datetime = "";
+ instance.time( datetime );
+ instance.time( datetime, null );
+ instance.time_();
+ }
+
+ /**
+ * Test of address method, of class SinkAdapter.
+ */
+ public void testAddress()
+ {
+ instance.address();
+ instance.address( null );
+ instance.address_();
+ }
+
+ /**
+ * Test of blockquote method, of class SinkAdapter.
+ */
+ public void testBlockquote()
+ {
+ instance.blockquote();
+ instance.blockquote( null );
+ instance.blockquote_();
+ }
+
+ /**
+ * Test of division method, of class SinkAdapter.
+ */
+ public void testDivision()
+ {
+ instance.division();
+ instance.division( null );
+ instance.division_();
+ }
+
+ /**
* Test of verbatim method, of class SinkAdapter.
*/
public void testVerbatim()
@@ -449,12 +561,22 @@
}
/**
+ * Test of inline method, of class SinkAdapter.
+ */
+ public void testInline()
+ {
+ instance.inline();
+ instance.inline( null );
+ instance.inline_();
+ }
+
+ /**
* Test of italic method, of class SinkAdapter.
*/
public void testItalic()
{
- instance.italic();
- instance.italic_();
+ instance.inline( SinkEventAttributeSet.Semantics.ITALIC );
+ instance.inline_();
}
/**
@@ -462,8 +584,8 @@
*/
public void testBold()
{
- instance.bold();
- instance.bold_();
+ instance.inline( SinkEventAttributeSet.Semantics.BOLD );
+ instance.inline_();
}
/**
@@ -471,8 +593,8 @@
*/
public void testMonospaced()
{
- instance.monospaced();
- instance.monospaced_();
+ instance.inline( SinkEventAttributeSet.Semantics.MONOSPACED );
+ instance.inline_();
}
/**
@@ -485,6 +607,15 @@
}
/**
+ * Test of lineBreakOpportunity method, of class SinkAdapter.
+ */
+ public void testLineBreakOpportunities()
+ {
+ instance.lineBreakOpportunity();
+ instance.lineBreakOpportunity( null );
+ }
+
+ /**
* Test of nonBreakingSpace method, of class SinkAdapter.
*/
public void testNonBreakingSpace()
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
index 492db2d..b9d4651 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkEventTestingSink.java
@@ -84,6 +84,42 @@
}
@Override
+ public void article()
+ {
+ addEvent( "article" );
+ }
+
+ @Override
+ public void article_()
+ {
+ addEvent( "article_" );
+ }
+
+ @Override
+ public void navigation()
+ {
+ addEvent( "navigation" );
+ }
+
+ @Override
+ public void navigation_()
+ {
+ addEvent( "navigation_" );
+ }
+
+ @Override
+ public void sidebar()
+ {
+ addEvent( "sidebar" );
+ }
+
+ @Override
+ public void sidebar_()
+ {
+ addEvent( "sidebar_" );
+ }
+
+ @Override
public void section1()
{
addEvent( "section1" );
@@ -408,6 +444,42 @@
}
@Override
+ public void header()
+ {
+ addEvent( "header" );
+ }
+
+ @Override
+ public void header_()
+ {
+ addEvent( "header_" );
+ }
+
+ @Override
+ public void content()
+ {
+ addEvent( "content" );
+ }
+
+ @Override
+ public void content_()
+ {
+ addEvent( "content_" );
+ }
+
+ @Override
+ public void footer()
+ {
+ addEvent( "footer" );
+ }
+
+ @Override
+ public void footer_()
+ {
+ addEvent( "footer_" );
+ }
+
+ @Override
public void paragraph()
{
addEvent( "paragraph" );
@@ -420,6 +492,66 @@
}
@Override
+ public void data( String value )
+ {
+ addEvent( "data", new Object[] {value} );
+ }
+
+ @Override
+ public void data_()
+ {
+ addEvent( "data_" );
+ }
+
+ @Override
+ public void time( String datetime )
+ {
+ addEvent( "time", new Object[] {datetime} );
+ }
+
+ @Override
+ public void time_()
+ {
+ addEvent( "time_" );
+ }
+
+ @Override
+ public void address()
+ {
+ addEvent( "address" );
+ }
+
+ @Override
+ public void address_()
+ {
+ addEvent( "address_" );
+ }
+
+ @Override
+ public void blockquote()
+ {
+ addEvent( "blockquote" );
+ }
+
+ @Override
+ public void blockquote_()
+ {
+ addEvent( "blockquote_" );
+ }
+
+ @Override
+ public void division()
+ {
+ addEvent( "division" );
+ }
+
+ @Override
+ public void division_()
+ {
+ addEvent( "division_" );
+ }
+
+ @Override
public void verbatim( boolean boxed )
{
addEvent( "verbatim", new Object[] {new Boolean( boxed )} );
@@ -546,6 +678,18 @@
}
@Override
+ public void inline()
+ {
+ addEvent( "inline" );
+ }
+
+ @Override
+ public void inline_()
+ {
+ addEvent( "inline_" );
+ }
+
+ @Override
public void italic()
{
addEvent( "italic" );
@@ -588,6 +732,12 @@
}
@Override
+ public void lineBreakOpportunity()
+ {
+ addEvent( "lineBreakOpportunity" );
+ }
+
+ @Override
public void nonBreakingSpace()
{
addEvent( "nonBreakingSpace" );
@@ -654,6 +804,24 @@
}
@Override
+ public void article( SinkEventAttributes attributes )
+ {
+ addEvent( "article", new Object[] {attributes} );
+ }
+
+ @Override
+ public void navigation( SinkEventAttributes attributes )
+ {
+ addEvent( "navigation", new Object[] {attributes} );
+ }
+
+ @Override
+ public void sidebar( SinkEventAttributes attributes )
+ {
+ addEvent( "sidebar", new Object[] {attributes} );
+ }
+
+ @Override
public void section( int level, SinkEventAttributes attributes )
{
addEvent( "section" + level, new Object[] {attributes} );
@@ -679,6 +847,24 @@
}
@Override
+ public void header( SinkEventAttributes attributes )
+ {
+ addEvent( "header", new Object[] {attributes} );
+ }
+
+ @Override
+ public void content( SinkEventAttributes attributes )
+ {
+ addEvent( "content", new Object[] {attributes} );
+ }
+
+ @Override
+ public void footer( SinkEventAttributes attributes )
+ {
+ addEvent( "footer", new Object[] {attributes} );
+ }
+
+ @Override
public void list( SinkEventAttributes attributes )
{
addEvent( "list", new Object[] {attributes} );
@@ -781,6 +967,36 @@
}
@Override
+ public void data( String value, SinkEventAttributes attributes )
+ {
+ addEvent( "data", new Object[] {value, attributes} );
+ }
+
+ @Override
+ public void time( String datetime, SinkEventAttributes attributes )
+ {
+ addEvent( "time", new Object[] {datetime, attributes} );
+ }
+
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ addEvent( "address", new Object[] {attributes} );
+ }
+
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ addEvent( "blockquote", new Object[] {attributes} );
+ }
+
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ addEvent( "division", new Object[] {attributes} );
+ }
+
+ @Override
public void verbatim( SinkEventAttributes attributes )
{
addEvent( "verbatim", new Object[] {attributes} );
@@ -805,12 +1021,24 @@
}
@Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ addEvent( "inline", new Object[] {attributes} );
+ }
+
+ @Override
public void lineBreak( SinkEventAttributes attributes )
{
addEvent( "lineBreak", new Object[] {attributes} );
}
@Override
+ public void lineBreakOpportunity( SinkEventAttributes attributes )
+ {
+ addEvent( "lineBreakOpportunity", new Object[] {attributes} );
+ }
+
+ @Override
public void text( String text, SinkEventAttributes attributes )
{
addEvent( "text", new Object[] {text, attributes} );
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkTestDocument.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkTestDocument.java
index 077d034..39626ca 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkTestDocument.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/SinkTestDocument.java
@@ -445,19 +445,19 @@
{
sink.paragraph();
- sink.italic();
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
sink.text( "Italic" );
- sink.italic_();
+ sink.inline_();
sink.text( " font. " );
- sink.bold();
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
sink.text( "Bold" );
- sink.bold_();
+ sink.inline_();
sink.text( " font. " );
- sink.monospaced();
- sink.text( "Monospaced" );
- sink.monospaced_();
+ sink.inline( SinkEventAttributeSet.Semantics.CODE );
+ sink.text( "Monospaced (code)" );
+ sink.inline_();
sink.text( " font." );
sink.paragraph_();
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/TextSink.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/TextSink.java
index 88cc712..7ec5b61 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/TextSink.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/TextSink.java
@@ -71,6 +71,42 @@
}
@Override
+ public void article()
+ {
+ writeln( "begin:article" );
+ }
+
+ @Override
+ public void article_()
+ {
+ writeln( "end:article" );
+ }
+
+ @Override
+ public void navigation()
+ {
+ writeln( "begin:navigation" );
+ }
+
+ @Override
+ public void navigation_()
+ {
+ writeln( "end:navigation" );
+ }
+
+ @Override
+ public void sidebar()
+ {
+ writeln( "begin:sidebar" );
+ }
+
+ @Override
+ public void sidebar_()
+ {
+ writeln( "end:sidebar" );
+ }
+
+ @Override
public void section1()
{
write( "begin:section1" );
@@ -395,6 +431,42 @@
}
@Override
+ public void header()
+ {
+ write( "begin:header" );
+ }
+
+ @Override
+ public void header_()
+ {
+ writeln( "end:header" );
+ }
+
+ @Override
+ public void content()
+ {
+ write( "begin:content" );
+ }
+
+ @Override
+ public void content_()
+ {
+ writeln( "end:content" );
+ }
+
+ @Override
+ public void footer()
+ {
+ write( "begin:footer" );
+ }
+
+ @Override
+ public void footer_()
+ {
+ writeln( "end:footer" );
+ }
+
+ @Override
public void paragraph()
{
write( "begin:paragraph" );
@@ -407,6 +479,66 @@
}
@Override
+ public void data( String value )
+ {
+ write( "begin:data, value: " + value );
+ }
+
+ @Override
+ public void data_()
+ {
+ writeln( "end:data" );
+ }
+
+ @Override
+ public void time( String datetime )
+ {
+ write( "begin:time, datetime: " + datetime );
+ }
+
+ @Override
+ public void time_()
+ {
+ writeln( "end:time" );
+ }
+
+ @Override
+ public void address()
+ {
+ write( "begin:address" );
+ }
+
+ @Override
+ public void address_()
+ {
+ writeln( "end:address" );
+ }
+
+ @Override
+ public void blockquote()
+ {
+ write( "begin:blockquote" );
+ }
+
+ @Override
+ public void blockquote_()
+ {
+ writeln( "end:blockquote" );
+ }
+
+ @Override
+ public void division()
+ {
+ write( "begin:division" );
+ }
+
+ @Override
+ public void division_()
+ {
+ writeln( "end:division" );
+ }
+
+ @Override
public void verbatim( boolean boxed )
{
write( "begin:verbatim, boxed: " + boxed );
@@ -533,6 +665,18 @@
}
@Override
+ public void inline()
+ {
+ write( "begin:inline" );
+ }
+
+ @Override
+ public void inline_()
+ {
+ writeln( "end:inline" );
+ }
+
+ @Override
public void italic()
{
write( "begin:italic" );
@@ -575,6 +719,12 @@
}
@Override
+ public void lineBreakOpportunity()
+ {
+ write( "lineBreakOpportunity" );
+ }
+
+ @Override
public void nonBreakingSpace()
{
write( "nonBreakingSpace" );
@@ -655,6 +805,24 @@
}
@Override
+ public void article( SinkEventAttributes attributes )
+ {
+ article();
+ }
+
+ @Override
+ public void navigation( SinkEventAttributes attributes )
+ {
+ navigation();
+ }
+
+ @Override
+ public void sidebar( SinkEventAttributes attributes )
+ {
+ sidebar();
+ }
+
+ @Override
public void section( int level, SinkEventAttributes attributes )
{
write( "begin:section" + level );
@@ -679,6 +847,24 @@
}
@Override
+ public void header( SinkEventAttributes attributes )
+ {
+ header();
+ }
+
+ @Override
+ public void content( SinkEventAttributes attributes )
+ {
+ content();
+ }
+
+ @Override
+ public void footer( SinkEventAttributes attributes )
+ {
+ footer();
+ }
+
+ @Override
public void list( SinkEventAttributes attributes )
{
list();
@@ -781,6 +967,36 @@
}
@Override
+ public void data( String value, SinkEventAttributes attributes )
+ {
+ data( value );
+ }
+
+ @Override
+ public void time( String datetime, SinkEventAttributes attributes )
+ {
+ time( datetime );
+ }
+
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ address();
+ }
+
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ blockquote();
+ }
+
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ division();
+ }
+
+ @Override
public void verbatim( SinkEventAttributes attributes )
{
boolean boxed = false;
@@ -813,12 +1029,24 @@
}
@Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ inline();
+ }
+
+ @Override
public void lineBreak( SinkEventAttributes attributes )
{
lineBreak();
}
@Override
+ public void lineBreakOpportunity( SinkEventAttributes attributes )
+ {
+ lineBreakOpportunity();
+ }
+
+ @Override
public void text( String text, SinkEventAttributes attributes )
{
text( text );
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/WellformednessCheckingSink.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/WellformednessCheckingSink.java
index c0ed641..01ddaef 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/WellformednessCheckingSink.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/WellformednessCheckingSink.java
@@ -66,6 +66,42 @@
}
@Override
+ public void article()
+ {
+ startElement( "article" );
+ }
+
+ @Override
+ public void article_()
+ {
+ checkWellformedness( "article" );
+ }
+
+ @Override
+ public void navigation()
+ {
+ startElement( "navigation" );
+ }
+
+ @Override
+ public void navigation_()
+ {
+ checkWellformedness( "navigation" );
+ }
+
+ @Override
+ public void sidebar()
+ {
+ startElement( "sidebar" );
+ }
+
+ @Override
+ public void sidebar_()
+ {
+ checkWellformedness( "sidebar" );
+ }
+
+ @Override
public void section1()
{
startElement( "section1" );
@@ -138,6 +174,42 @@
}
@Override
+ public void header()
+ {
+ startElement( "header" );
+ }
+
+ @Override
+ public void header_()
+ {
+ checkWellformedness( "header" );
+ }
+
+ @Override
+ public void content()
+ {
+ startElement( "content" );
+ }
+
+ @Override
+ public void content_()
+ {
+ checkWellformedness( "content" );
+ }
+
+ @Override
+ public void footer()
+ {
+ startElement( "footer" );
+ }
+
+ @Override
+ public void footer_()
+ {
+ checkWellformedness( "footer" );
+ }
+
+ @Override
public void list()
{
startElement( "list" );
@@ -403,6 +475,66 @@
}
@Override
+ public void data( String value )
+ {
+ startElement( "data" );
+ }
+
+ @Override
+ public void data_()
+ {
+ checkWellformedness( "data" );
+ }
+
+ @Override
+ public void time( String datetime )
+ {
+ startElement( "time" );
+ }
+
+ @Override
+ public void time_()
+ {
+ checkWellformedness( "time" );
+ }
+
+ @Override
+ public void address()
+ {
+ startElement( "address" );
+ }
+
+ @Override
+ public void address_()
+ {
+ checkWellformedness( "address" );
+ }
+
+ @Override
+ public void blockquote()
+ {
+ startElement( "blockquote" );
+ }
+
+ @Override
+ public void blockquote_()
+ {
+ checkWellformedness( "blockquote" );
+ }
+
+ @Override
+ public void division()
+ {
+ startElement( "division" );
+ }
+
+ @Override
+ public void division_()
+ {
+ checkWellformedness( "division" );
+ }
+
+ @Override
public void verbatim( boolean boxed )
{
startElement( "verbatim" );
@@ -529,6 +661,18 @@
}
@Override
+ public void inline()
+ {
+ startElement( "inline" );
+ }
+
+ @Override
+ public void inline_()
+ {
+ checkWellformedness( "inline" );
+ }
+
+ @Override
public void italic()
{
startElement( "italic" );
@@ -571,6 +715,12 @@
}
@Override
+ public void lineBreakOpportunity()
+ {
+ // nop
+ }
+
+ @Override
public void nonBreakingSpace()
{
// nop
@@ -702,6 +852,24 @@
}
@Override
+ public void article( SinkEventAttributes attributes )
+ {
+ article();
+ }
+
+ @Override
+ public void navigation( SinkEventAttributes attributes )
+ {
+ navigation();
+ }
+
+ @Override
+ public void sidebar( SinkEventAttributes attributes )
+ {
+ sidebar();
+ }
+
+ @Override
public void section( int level, SinkEventAttributes attributes )
{
startElement( "section" + level );
@@ -726,6 +894,24 @@
}
@Override
+ public void header( SinkEventAttributes attributes )
+ {
+ header();
+ }
+
+ @Override
+ public void content( SinkEventAttributes attributes )
+ {
+ content();
+ }
+
+ @Override
+ public void footer( SinkEventAttributes attributes )
+ {
+ footer();
+ }
+
+ @Override
public void list( SinkEventAttributes attributes )
{
list();
@@ -828,6 +1014,36 @@
}
@Override
+ public void data( String value, SinkEventAttributes attributes )
+ {
+ data( value );
+ }
+
+ @Override
+ public void time( String datetime, SinkEventAttributes attributes )
+ {
+ time( datetime );
+ }
+
+ @Override
+ public void address( SinkEventAttributes attributes )
+ {
+ address();
+ }
+
+ @Override
+ public void blockquote( SinkEventAttributes attributes )
+ {
+ blockquote();
+ }
+
+ @Override
+ public void division( SinkEventAttributes attributes )
+ {
+ division();
+ }
+
+ @Override
public void verbatim( SinkEventAttributes attributes )
{
verbatim( false );
@@ -852,12 +1068,24 @@
}
@Override
+ public void inline( SinkEventAttributes attributes )
+ {
+ inline();
+ }
+
+ @Override
public void lineBreak( SinkEventAttributes attributes )
{
lineBreak();
}
@Override
+ public void lineBreakOpportunity( SinkEventAttributes attributes )
+ {
+ lineBreakOpportunity();
+ }
+
+ @Override
public void text( String text, SinkEventAttributes attributes )
{
text( text );
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java
new file mode 100644
index 0000000..4d0723f
--- /dev/null
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/Xhtml5BaseSinkTest.java
@@ -0,0 +1,1476 @@
+package org.apache.maven.doxia.sink.impl;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.StringWriter;
+import java.io.Writer;
+
+import javax.swing.text.html.HTML.Attribute;
+
+import junit.framework.TestCase;
+
+import org.apache.maven.doxia.markup.Markup;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.SinkEventAttributes;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+import org.apache.maven.doxia.sink.impl.Xhtml5BaseSink;
+
+/**
+ * Test for Xhtml5BaseSink.
+ */
+public class Xhtml5BaseSinkTest
+ extends TestCase
+{
+ protected static final String LS = Markup.EOL;
+ private final SinkEventAttributes attributes = SinkEventAttributeSet.BOLD;
+ private Xhtml5BaseSink sink;
+ private Writer writer;
+
+ String EOL = System.lineSeparator();
+
+ @Override
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ writer = new StringWriter();
+ }
+
+ public void testSpaceAfterClosingTag()
+ throws Exception
+ {
+ // DOXIA-189
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.paragraph();
+ sink.text( "There should be no space before the " );
+ sink.italic();
+ sink.text( "period" );
+ sink.italic_();
+ sink.text( "." );
+ sink.paragraph_();
+ }
+ finally
+ {
+ if ( sink != null )
+ {
+ sink.close();
+ }
+ }
+
+ String actual = writer.toString();
+ String expected = "<p>There should be no space before the <i>period</i>.</p>";
+
+ assertEquals( expected, actual );
+ }
+
+ /**
+ * @throws Exception if any
+ */
+ public void testNestedTables()
+ throws Exception
+ {
+ // DOXIA-177
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.table();
+ sink.tableRows( new int[] { Sink.JUSTIFY_CENTER }, false );
+ sink.tableRow();
+ sink.tableCell();
+ sink.text( "cell11" );
+ sink.tableCell_();
+ sink.tableCell();
+ sink.text( "cell12" );
+ sink.tableCell_();
+ sink.tableRow_();
+
+ sink.tableRow();
+ sink.tableCell();
+ sink.table( SinkEventAttributeSet.LEFT );
+ sink.tableRows( new int[] { Sink.JUSTIFY_LEFT }, false );
+ sink.tableRow();
+ sink.tableCell();
+ sink.text( "nestedTable1Cell11" );
+ sink.tableCell_();
+ sink.tableCell();
+ sink.text( "nestedTable1Cell12" );
+ sink.tableCell_();
+ sink.tableRow_();
+ sink.tableRow();
+ sink.tableCell();
+
+ sink.table( SinkEventAttributeSet.RIGHT );
+ sink.tableRows( new int[] { Sink.JUSTIFY_RIGHT }, false );
+ sink.tableRow();
+ sink.tableCell();
+ sink.text( "nestedTable2Cell11" );
+ sink.tableCell_();
+ sink.tableCell();
+ sink.text( "nestedTable2Cell12" );
+ sink.tableCell_();
+ sink.tableRow_();
+ sink.tableRow();
+ sink.tableCell();
+ sink.text( "nestedTable2Cell21" );
+ sink.tableCell_();
+ sink.tableCell();
+ sink.text( "nestedTable2Cell22" );
+ sink.tableCell_();
+ sink.tableRow_();
+ sink.tableRows_();
+ sink.tableCaption();
+ sink.text( "caption3" );
+ sink.tableCaption_();
+ sink.table_();
+
+ sink.tableCell_();
+ sink.tableCell();
+ sink.text( "nestedTable1Cell22" );
+ sink.tableCell_();
+ sink.tableRow_();
+ sink.tableRows_();
+ sink.tableCaption();
+ sink.text( "caption2" );
+ sink.tableCaption_();
+ sink.table_();
+
+ sink.tableCell_();
+ sink.tableCell();
+ sink.text( "cell22" );
+ sink.tableCell_();
+ sink.tableRow_();
+ sink.tableRows_();
+ sink.tableCaption();
+ sink.text( "caption1" );
+ sink.tableCaption_();
+ sink.table_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ String actual = writer.toString();
+ assertTrue( actual.indexOf( "<table align=\"center\" border=\"0\" class=\"bodyTable\">"
+ + "<caption>caption1</caption>" ) != 1 );
+ assertTrue( actual.indexOf( "<table border=\"0\" class=\"bodyTable\" align=\"left\">"
+ + "<caption>caption2</caption>" ) != 1 );
+ assertTrue( actual.indexOf( "<table align=\"center\" border=\"0\" class=\"bodyTable\">"
+ + "<caption>caption3</caption>" ) != 1 );
+
+ assertTrue( actual.indexOf( "<td align=\"center\">cell11</td>" ) != 1 );
+ assertTrue( actual.indexOf( "<td align=\"left\">nestedTable1Cell11</td>" ) != 1 );
+ assertTrue( actual.indexOf( "<td align=\"right\">nestedTable2Cell11</td>" ) != 1 );
+ assertTrue( actual.indexOf( "<td align=\"left\">nestedTable1Cell22</td>" ) != 1 );
+ assertTrue( actual.indexOf( "<td align=\"center\">cell22</td>" ) != 1 );
+ }
+
+ /**
+ * Test of article method, of class Xhtml5BaseSink.
+ */
+ public void testArticle()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.article();
+ sink.article_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<article></article>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.article( attributes );
+ sink.article_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<article style=\"bold\"></article>", writer.toString() );
+ }
+
+ /**
+ * Test of navigation method, of class Xhtml5BaseSink.
+ */
+ public void testNavigation()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.navigation();
+ sink.navigation_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<nav></nav>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.navigation( attributes );
+ sink.navigation_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<nav style=\"bold\"></nav>", writer.toString() );
+ }
+
+ /**
+ * Test of sidebar method, of class Xhtml5BaseSink.
+ */
+ public void testSidebar()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.sidebar();
+ sink.sidebar_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<aside></aside>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.sidebar( attributes );
+ sink.sidebar_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<aside style=\"bold\"></aside>", writer.toString() );
+ }
+
+ /**
+ * Test of section method, of class Xhtml5BaseSink.
+ */
+ public void testSection()
+ {
+ final int level = Xhtml5BaseSink.SECTION_LEVEL_1;
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section( level, attributes );
+ sink.sectionTitle( level, attributes );
+ sink.sectionTitle_( level );
+ sink.section_( level );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section style=\"bold\">" + LS + "<h2 style=\"bold\"></h2></section>", writer.toString() );
+ }
+
+ /**
+ * Test of section method, of class Xhtml5BaseSink.
+ */
+ public void testSectionAttributes()
+ {
+ final int level = Xhtml5BaseSink.SECTION_LEVEL_1;
+ final SinkEventAttributeSet set = new SinkEventAttributeSet(
+ new String[] {"name", "section name", "class", "foo", "id", "bar"} );
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section( level, set );
+ sink.sectionTitle( level, null );
+ sink.sectionTitle_( level );
+ sink.section_( level );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section class=\"foo\" id=\"bar\">" + LS + "<h2></h2></section>", writer.toString() );
+ }
+
+ /**
+ * Test of section1 method, of class Xhtml5BaseSink.
+ */
+ public void testSection1()
+ {
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section1();
+ sink.sectionTitle1();
+ sink.sectionTitle1_();
+ sink.section1_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section>" + LS + "<h2></h2></section>", writer.toString() );
+ }
+
+ /**
+ * Test of section2 method, of class Xhtml5BaseSink.
+ */
+ public void testSection2()
+ {
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section2();
+ sink.sectionTitle2();
+ sink.sectionTitle2_();
+ sink.section2_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section>" + LS + "<h3></h3></section>", writer.toString() );
+ }
+
+ /**
+ * Test of section3 method, of class Xhtml5BaseSink.
+ */
+ public void testSection3()
+ {
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section3();
+ sink.sectionTitle3();
+ sink.sectionTitle3_();
+ sink.section3_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section>" + LS + "<h4></h4></section>", writer.toString() );
+ }
+
+ /**
+ * Test of section4 method, of class Xhtml5BaseSink.
+ */
+ public void testSection4()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section4();
+ sink.sectionTitle4();
+ sink.sectionTitle4_();
+ sink.section4_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section>" + LS + "<h5></h5></section>", writer.toString() );
+ }
+
+ /**
+ * Test of section5 method, of class Xhtml5BaseSink.
+ */
+ public void testSection5()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.section5();
+ sink.sectionTitle5();
+ sink.sectionTitle5_();
+ sink.section5_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section>" + LS + "<h6></h6></section>", writer.toString() );
+ }
+
+ /**
+ * Test of header method, of class Xhtml5BaseSink.
+ */
+ public void testHeader()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.header();
+ sink.header_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<header></header>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.header( attributes );
+ sink.header_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<header style=\"bold\"></header>", writer.toString() );
+ }
+
+ /**
+ * Test of content method, of class Xhtml5BaseSink.
+ */
+ public void testContent()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.content();
+ sink.content();
+ sink.content_();
+ sink.content_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<main>" + EOL + "<div class=\"content\"></div></main>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.content( attributes );
+ sink.content( attributes );
+ sink.content_();
+ sink.content_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<main style=\"bold\">" + EOL + "<div style=\"bold\" class=\"content\"></div></main>", writer.toString() );
+ }
+
+ /**
+ * Test of footer method, of class Xhtml5BaseSink.
+ */
+ public void testFooter()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.footer();
+ sink.footer_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<footer></footer>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.footer( attributes );
+ sink.footer_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<footer style=\"bold\"></footer>", writer.toString() );
+ }
+
+ /**
+ * Test of list method, of class Xhtml5BaseSink.
+ * @throws java.lang.Exception if any.
+ */
+ public void testList()
+ throws Exception
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.list();
+ sink.listItem();
+ sink.listItem_();
+ sink.list_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<ul>" + LS + "<li></li></ul>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.list( attributes );
+ sink.listItem( attributes );
+ sink.listItem_();
+ sink.list_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<ul style=\"bold\">" + LS + "<li style=\"bold\"></li></ul>", writer.toString() );
+ }
+
+ /**
+ * Test of numberedList method, of class Xhtml5BaseSink.
+ */
+ public void testNumberedList()
+ {
+ final int numbering = Xhtml5BaseSink.NUMBERING_DECIMAL;
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.numberedList( numbering );
+ sink.numberedListItem();
+ sink.numberedListItem_();
+ sink.numberedList_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<ol style=\"list-style-type: decimal\">" + LS + "<li></li></ol>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.numberedList( numbering, attributes );
+ sink.numberedListItem( attributes );
+ sink.numberedListItem_();
+ sink.numberedList_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<ol style=\"list-style-type: decimal\">" + LS + "<li style=\"bold\"></li></ol>", writer.toString() );
+ }
+
+ /**
+ * Test of definitionList method, of class Xhtml5BaseSink.
+ */
+ public void testDefinitionList()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.definitionList();
+ sink.definedTerm();
+ sink.definedTerm_();
+ sink.definition();
+ sink.definition_();
+ sink.definitionList_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<dl>" + LS + "<dt></dt>" + LS + "<dd></dd></dl>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.definitionList( attributes );
+ sink.definedTerm( attributes );
+ sink.definedTerm_();
+ sink.definition( attributes );
+ sink.definition_();
+ sink.definitionList_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<dl style=\"bold\">" + LS + "<dt style=\"bold\"></dt>" + LS + "<dd style=\"bold\"></dd></dl>", writer.toString() );
+ }
+
+ /**
+ * Test of figure method, of class Xhtml5BaseSink.
+ */
+ public void testFigure()
+ {
+ final String src = "src.jpg";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.figure( attributes );
+ sink.figureGraphics( src, attributes );
+ sink.figureCaption( attributes );
+ sink.figureCaption_();
+ sink.figure_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<figure style=\"bold\">"
+ + "<img src=\"src.jpg\" style=\"bold\" alt=\"\" />"
+ + "<figcaption style=\"bold\"></figcaption></figure>", writer.toString() );
+ }
+
+ /**
+ * Test of figureGraphics method, of class Xhtml5BaseSink.
+ */
+ public void testFigureGraphics()
+ {
+ String src = "source.png";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.figureGraphics( src, attributes );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<img src=\"source.png\" style=\"bold\" alt=\"\" />", writer.toString() );
+ }
+
+ /**
+ * Test of paragraph method, of class Xhtml5BaseSink.
+ */
+ public void testParagraph()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.paragraph();
+ sink.paragraph_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<p></p>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.paragraph( attributes );
+ sink.paragraph_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<p style=\"bold\"></p>", writer.toString() );
+ }
+
+ /**
+ * Test of data method, of class Xhtml5BaseSink.
+ */
+ public void testData()
+ {
+ String value = "value";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.data( value, attributes );
+ sink.data_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<data value=\"value\" style=\"bold\"></data>", writer.toString() );
+ }
+
+ /**
+ * Test of time method, of class Xhtml5BaseSink.
+ */
+ public void testTime()
+ {
+ String datetime = "datetime";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.time( datetime, attributes );
+ sink.time_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<time datetime=\"datetime\" style=\"bold\"></time>", writer.toString() );
+ }
+
+ /**
+ * Test of address method, of class Xhtml5BaseSink.
+ */
+ public void testAddress()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.address();
+ sink.address_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<address></address>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.address( attributes );
+ sink.address_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<address style=\"bold\"></address>", writer.toString() );
+ }
+
+ /**
+ * Test of blockquote method, of class Xhtml5BaseSink.
+ */
+ public void testBlockquote()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.blockquote();
+ sink.blockquote_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<blockquote></blockquote>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.blockquote( attributes );
+ sink.blockquote_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<blockquote style=\"bold\"></blockquote>", writer.toString() );
+ }
+
+ /**
+ * Test of division method, of class Xhtml5BaseSink.
+ */
+ public void testDivision()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.division();
+ sink.division_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<div></div>", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.division( attributes );
+ sink.division_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<div style=\"bold\"></div>", writer.toString() );
+ }
+
+ /**
+ * Test of verbatim method, of class Xhtml5BaseSink.
+ */
+ public void testVerbatim()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.verbatim( true );
+ sink.verbatim_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<div class=\"source\">" + LS + "<pre></pre></div>", writer.toString() );
+
+ checkVerbatimAttributes( attributes, "<div>" + LS + "<pre style=\"bold\"></pre></div>" );
+
+ final SinkEventAttributes att =
+ new SinkEventAttributeSet( new String[] {SinkEventAttributes.ID, "id"} );
+ checkVerbatimAttributes( att, "<div>" + LS + "<pre id=\"id\"></pre></div>" );
+
+ att.addAttribute( Attribute.CLASS, "class" );
+ checkVerbatimAttributes( att, "<div>" + LS + "<pre id=\"id\" class=\"class\"></pre></div>" );
+
+ att.addAttribute( SinkEventAttributes.DECORATION, "boxed" );
+ checkVerbatimAttributes( att, "<div class=\"source\">" + LS + "<pre id=\"id\" class=\"class\"></pre></div>" );
+
+ att.removeAttribute( Attribute.CLASS.toString() );
+ checkVerbatimAttributes( att, "<div class=\"source\">" + LS + "<pre id=\"id\"></pre></div>" );
+ }
+
+ private void checkVerbatimAttributes( final SinkEventAttributes att, final String expected )
+ {
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.verbatim( att );
+ sink.verbatim_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( expected, writer.toString() );
+ }
+
+ /**
+ * Test of horizontalRule method, of class Xhtml5BaseSink.
+ */
+ public void testHorizontalRule()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.horizontalRule();
+ sink.horizontalRule( attributes );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<hr /><hr style=\"bold\" />", writer.toString() );
+ }
+
+ /**
+ * Test of table method, of class Xhtml5BaseSink.
+ */
+ public void testTable()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.table( attributes );
+ sink.table_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "</table>", writer.toString() );
+ }
+
+ /**
+ * Test of tableRows method, of class Xhtml5BaseSink.
+ */
+ public void testTableRows()
+ {
+ final int[] justification = null;
+ final boolean grid = false;
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.tableRows( justification, grid );
+ sink.tableRows_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<table border=\"0\" class=\"bodyTable\">", writer.toString() );
+ }
+
+ /**
+ * Test of tableRow method, of class Xhtml5BaseSink.
+ */
+ public void testTableRow()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.tableRow( attributes );
+ sink.tableRow_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<tr class=\"a\" style=\"bold\"></tr>", writer.toString() );
+ }
+
+ /**
+ * Test of tableCell method, of class Xhtml5BaseSink.
+ */
+ public void testTableCell()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.tableCell( attributes );
+ sink.tableCell_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<td style=\"bold\"></td>", writer.toString() );
+ }
+
+ /**
+ * Test of tableHeaderCell method, of class Xhtml5BaseSink.
+ */
+ public void testTableHeaderCell()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.tableHeaderCell( attributes );
+ sink.tableHeaderCell_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<th style=\"bold\"></th>", writer.toString() );
+ }
+
+ /**
+ * Test of tableCaption method, of class Xhtml5BaseSink.
+ */
+ public void testTableCaption()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.table();
+ sink.tableRows( null, false );
+ sink.tableCaption( attributes );
+ sink.text( "caption" );
+ sink.tableCaption_();
+ sink.tableRows_();
+ sink.table_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<table border=\"0\" class=\"bodyTable\">" +
+ "<caption style=\"bold\">caption</caption></table>", writer.toString() );
+ }
+
+ /**
+ * Test of anchor method, of class Xhtml5BaseSink.
+ */
+ public void testAnchor()
+ {
+ String name = "anchor";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.anchor( name, attributes );
+ sink.anchor_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<a name=\"anchor\" style=\"bold\"></a>", writer.toString() );
+ }
+
+ /**
+ * Test of link method, of class Xhtml5BaseSink.
+ */
+ public void testLink()
+ {
+ final String name = "link.html";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.link( name, attributes );
+ sink.link_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<a href=\"link.html\" style=\"bold\"></a>", writer.toString() );
+ }
+
+ /**
+ * Test of inline method, of class Xhtml5BaseSink.
+ */
+ public void testInline()
+ {
+ String text = "a text & \u00c6";
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.inline( SinkEventAttributeSet.Semantics.EMPHASIS );
+ sink.inline( SinkEventAttributeSet.Semantics.STRONG );
+ sink.inline( SinkEventAttributeSet.Semantics.SMALL );
+ sink.inline( SinkEventAttributeSet.Semantics.LINE_THROUGH );
+ sink.inline( SinkEventAttributeSet.Semantics.CITATION );
+ sink.inline( SinkEventAttributeSet.Semantics.QUOTE );
+ sink.inline( SinkEventAttributeSet.Semantics.DEFINITION );
+ sink.inline( SinkEventAttributeSet.Semantics.ABBREVIATION );
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
+ sink.inline( SinkEventAttributeSet.Semantics.CODE );
+ sink.inline( SinkEventAttributeSet.Semantics.VARIABLE );
+ sink.inline( SinkEventAttributeSet.Semantics.SAMPLE );
+ sink.inline( SinkEventAttributeSet.Semantics.KEYBOARD );
+ sink.inline( SinkEventAttributeSet.Semantics.SUPERSCRIPT );
+ sink.inline( SinkEventAttributeSet.Semantics.SUBSCRIPT );
+ sink.inline( SinkEventAttributeSet.Semantics.ANNOTATION );
+ sink.inline( SinkEventAttributeSet.Semantics.HIGHLIGHT );
+ sink.inline( SinkEventAttributeSet.Semantics.RUBY );
+ sink.inline( SinkEventAttributeSet.Semantics.RUBY_BASE );
+ sink.inline( SinkEventAttributeSet.Semantics.RUBY_TEXT );
+ sink.inline( SinkEventAttributeSet.Semantics.RUBY_TEXT_CONTAINER );
+ sink.inline( SinkEventAttributeSet.Semantics.RUBY_PARANTHESES );
+ sink.inline( SinkEventAttributeSet.Semantics.BIDIRECTIONAL_ISOLATION );
+ sink.inline( SinkEventAttributeSet.Semantics.BIDIRECTIONAL_OVERRIDE );
+ sink.inline( SinkEventAttributeSet.Semantics.PHRASE );
+ sink.inline( SinkEventAttributeSet.Semantics.INSERT );
+ sink.inline( SinkEventAttributeSet.Semantics.DELETE );
+ sink.text( text );
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ sink.inline_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<em><strong><small><s><cite><q><dfn><abbr><i><b><code><var><samp><kbd><sup><sub><u><mark><ruby><rb><rt><rtc><rp><bdi><bdo><span><ins><del>a text & Æ</del></ins></span></bdo></bdi></rp></rtc></rt></rb></ruby></mark></u></sub></sup></kbd></samp></var></code></b></i></abbr></dfn></q></cite></s></small></strong></em>", writer.toString() );
+ }
+
+ /**
+ * Test of italic/bold/code method, of class Xhtml5BaseSink.
+ */
+ public void testItalic()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
+ sink.inline_();
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
+ sink.inline_();
+ sink.inline( SinkEventAttributeSet.Semantics.CODE );
+ sink.inline_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<i></i><b></b><code></code>", writer.toString() );
+ }
+
+ /**
+ * Test of lineBreak/lineBreakOpportunity/pageBreak/nonBreakingSpace method, of class Xhtml5BaseSink.
+ */
+ public void testLineBreak()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.lineBreak( attributes );
+ sink.lineBreakOpportunity( attributes );
+ sink.pageBreak();
+ sink.nonBreakingSpace();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<br style=\"bold\" /><wbr style=\"bold\" /><!-- PB --> ", writer.toString() );
+ }
+
+ /**
+ * Test of text method, of class Xhtml5BaseSink.
+ */
+ public void testText()
+ {
+ String text = "a text & \u00c6";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.text( text );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "a text & Æ", writer.toString() );
+
+ writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.text( text, attributes );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "a text & Æ", writer.toString() );
+ }
+
+ /**
+ * Test of rawText method, of class Xhtml5BaseSink.
+ */
+ public void testRawText()
+ {
+ String text = "raw text";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.rawText( text );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "raw text", writer.toString() );
+ }
+
+ /**
+ * Test of comment method, of class Xhtml5BaseSink.
+ */
+ public void testComment()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.comment( "a comment" );
+ sink.comment( " a comment" );
+ sink.comment( "a comment " );
+ sink.comment( " a comment " );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<!--a comment--><!-- a comment--><!--a comment --><!-- a comment -->", writer.toString() );
+ }
+
+ /**
+ * Test of unknown method, of class Xhtml5BaseSink.
+ */
+ public void testUnknown()
+ {
+ final String name = "unknown";
+ final Object[] requiredParams = null;
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.unknown( name, requiredParams, attributes );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "", writer.toString() );
+ }
+
+ /**
+ * Test entities in attribute values.
+ */
+ public void testAttributeEntities()
+ {
+ final Object[] startTag = new Object[] { new Integer( Xhtml5BaseSink.TAG_TYPE_START ) };
+ final Object[] endTag = new Object[] { new Integer( Xhtml5BaseSink.TAG_TYPE_END ) };
+ final String script = Xhtml5BaseSink.SCRIPT.toString();
+ final SinkEventAttributes src = new SinkEventAttributeSet(
+ new String[] {SinkEventAttributes.SRC.toString(), "http://ex.com/ex.js?v=l&l=e"} );
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+
+ sink.unknown( script, startTag, src );
+ sink.unknown( script, endTag, null );
+
+ sink.figureGraphics( "http://ex.com/ex.jpg?v=l&l=e", src );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ String result = writer.toString();
+
+ assertTrue( result.contains( "ex.js?v=l&l=e" ) );
+ assertTrue( result.contains( "ex.jpg?v=l&l=e" ) );
+ }
+
+ /**
+ * Test of entity.
+ */
+ public void testEntity()
+ {
+ // DOXIA-314
+ String text = "a text '𝟭'";
+
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.text( text );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "a text '𝟭'", writer.toString() );
+ }
+
+ /**
+ * Test unicode chracters in tables. DOXIA-433.
+ */
+ public void testSpecialCharacters()
+ {
+ try
+ {
+ sink = new Xhtml5BaseSink( writer );
+ sink.table( null );
+ sink.tableRows( null, true );
+ sink.tableRow( null );
+ sink.tableCell();
+ sink.text( "\u2713", null );
+ sink.tableCell_();
+ sink.tableRow_();
+ sink.tableRows_();
+ sink.table_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ final String result = writer.toString();
+
+ assertTrue( result.contains( "✓" ) );
+ }
+}
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSinkTest.java b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSinkTest.java
index 9672138..0efe53a 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSinkTest.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/sink/impl/XhtmlBaseSinkTest.java
@@ -65,9 +65,9 @@
sink.paragraph();
sink.text( "There should be no space before the " );
- sink.italic();
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
sink.text( "period" );
- sink.italic_();
+ sink.inline_();
sink.text( "." );
sink.paragraph_();
}
@@ -816,12 +816,12 @@
try
{
sink = new XhtmlBaseSink( writer );
- sink.italic();
- sink.italic_();
- sink.bold();
- sink.bold_();
- sink.monospaced();
- sink.monospaced_();
+ sink.inline( SinkEventAttributeSet.Semantics.ITALIC );
+ sink.inline_();
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
+ sink.inline_();
+ sink.inline( SinkEventAttributeSet.Semantics.MONOSPACED );
+ sink.inline_();
}
finally
{
diff --git a/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidator.java b/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidator.java
index 80e38f3..69a78f3 100644
--- a/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidator.java
+++ b/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidator.java
@@ -60,7 +60,10 @@
/** XMLReader to validate xml file */
private XMLReader xmlReader;
- /**
+ /** HTML5 does not have a DTD or XSD, include option to disable validation */
+ private boolean validate = true;
+
+ /**
* Filter fail message.
*
* @param message not null
@@ -150,6 +153,22 @@
*/
protected abstract EntityResolver getEntityResolver();
+ /**
+ * Returns whether the XMLReader should validate XML.
+ * @return true if validation should be performed, false otherwise.
+ */
+ protected boolean isValidate() {
+ return validate;
+ }
+
+ /**
+ * Sets whether the XMLReader should validate XML.
+ * @param validate true if validation should be performed, false otherwise.
+ */
+ protected void setValidate(boolean validate) {
+ this.validate = validate;
+ }
+
// ----------------------------------------------------------------------
// Private methods
// ----------------------------------------------------------------------
@@ -161,8 +180,8 @@
try
{
xmlReader = XMLReaderFactory.createXMLReader( "org.apache.xerces.parsers.SAXParser" );
- xmlReader.setFeature( "http://xml.org/sax/features/validation", true );
- xmlReader.setFeature( "http://apache.org/xml/features/validation/schema", true );
+ xmlReader.setFeature( "http://xml.org/sax/features/validation", validate );
+ xmlReader.setFeature( "http://apache.org/xml/features/validation/schema", validate );
xmlReader.setErrorHandler( new MessagesErrorHandler() );
xmlReader.setEntityResolver( getEntityResolver() );
}
diff --git a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
index 6bdd0a4..b232c4e 100644
--- a/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
+++ b/doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptSink.java
@@ -21,10 +21,13 @@
import java.io.PrintWriter;
import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Stack;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractTextSink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.codehaus.plexus.util.StringUtils;
/**
@@ -104,6 +107,9 @@
/** listStyles. */
private final Stack<String> listStyles;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<String>> inlineStack = new Stack<List<String>>();
+
// ----------------------------------------------------------------------
// Public protected methods
// ----------------------------------------------------------------------
@@ -178,6 +184,7 @@
this.cellJustif = null;
this.rowLine = null;
this.listStyles.clear();
+ this.inlineStack.clear();
}
/**
@@ -810,57 +817,91 @@
}
/** {@inheritDoc} */
- public void italic()
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
{
if ( !headerFlag )
{
- write( ITALIC_START_MARKUP );
+ List<String> tags = new ArrayList<String>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ write( ITALIC_START_MARKUP );
+ tags.add( 0, ITALIC_END_MARKUP );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ write( BOLD_START_MARKUP );
+ tags.add( 0, BOLD_END_MARKUP );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ write( MONOSPACED_START_MARKUP );
+ tags.add( 0, MONOSPACED_END_MARKUP );
+ }
+
+ }
+
+ inlineStack.push( tags );
}
}
/** {@inheritDoc} */
+ public void inline_()
+ {
+ if ( !headerFlag )
+ {
+ for ( String tag: inlineStack.pop() )
+ {
+ write( tag );
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void italic()
+ {
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
+ }
+
+ /** {@inheritDoc} */
public void italic_()
{
- if ( !headerFlag )
- {
- write( ITALIC_END_MARKUP );
- }
+ inline_();
}
/** {@inheritDoc} */
public void bold()
{
- if ( !headerFlag )
- {
- write( BOLD_START_MARKUP );
- }
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void bold_()
{
- if ( !headerFlag )
- {
- write( BOLD_END_MARKUP );
- }
+ inline_();
}
/** {@inheritDoc} */
public void monospaced()
{
- if ( !headerFlag )
- {
- write( MONOSPACED_START_MARKUP );
- }
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/** {@inheritDoc} */
public void monospaced_()
{
- if ( !headerFlag )
- {
- write( MONOSPACED_END_MARKUP );
- }
+ inline_();
}
/** {@inheritDoc} */
diff --git a/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java b/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java
index 50cf0d9..2a946b8 100644
--- a/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java
+++ b/doxia-modules/doxia-module-apt/src/test/java/org/apache/maven/doxia/module/apt/AptSinkTest.java
@@ -83,6 +83,24 @@
}
/** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getSectionTitleBlock( String title )
{
return title;
@@ -122,6 +140,24 @@
}
/** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getListBlock( String item )
{
return EOL + EOL + Markup.SPACE + "" + AptMarkup.LIST_START_MARKUP + "" + Markup.SPACE + item + EOL + EOL
@@ -171,6 +207,36 @@
}
/** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getVerbatimBlock( String text )
{
return EOL + EOL + AptMarkup.BOXED_VERBATIM_START_MARKUP + EOL + text + EOL
@@ -203,6 +269,30 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return AptMarkup.ITALIC_START_MARKUP + text + AptMarkup.ITALIC_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return AptMarkup.BOLD_START_MARKUP + text + AptMarkup.BOLD_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return AptMarkup.MONOSPACED_START_MARKUP + text + AptMarkup.MONOSPACED_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return AptMarkup.ITALIC_START_MARKUP + text + AptMarkup.ITALIC_END_MARKUP;
@@ -217,7 +307,7 @@
/** {@inheritDoc} */
protected String getMonospacedBlock( String text )
{
- return AptMarkup.MONOSPACED_START_MARKUP + text + AptMarkup.MONOSPACED_END_MARKUP;
+ return text;
}
/** {@inheritDoc} */
@@ -227,6 +317,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return AptMarkup.NON_BREAKING_SPACE_MARKUP;
diff --git a/doxia-modules/doxia-module-confluence/src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceSink.java b/doxia-modules/doxia-module-confluence/src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceSink.java
index b8f2b90..4aa968a 100644
--- a/doxia-modules/doxia-module-confluence/src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceSink.java
+++ b/doxia-modules/doxia-module-confluence/src/main/java/org/apache/maven/doxia/module/confluence/ConfluenceSink.java
@@ -22,12 +22,15 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Stack;
import javax.swing.text.html.HTML.Attribute;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractTextSink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.apache.maven.doxia.util.HtmlTools;
import org.codehaus.plexus.util.StringUtils;
@@ -61,6 +64,9 @@
/** An indication on if we're in monospaced mode. */
private boolean monospacedFlag;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<String>> inlineStack = new Stack<List<String>>();
+
/** An indication on if we're in verbatim box mode. */
private boolean verbatimBoxedFlag;
@@ -159,13 +165,13 @@
/** {@inheritDoc} */
public void bold()
{
- write( BOLD_START_MARKUP );
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void bold_()
{
- write( BOLD_END_MARKUP );
+ inline_();
}
/**
@@ -417,15 +423,67 @@
}
/** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ if ( !headFlag )
+ {
+ List<String> tags = new ArrayList<String>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ write( ITALIC_START_MARKUP );
+ tags.add( 0, ITALIC_END_MARKUP );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ write( BOLD_START_MARKUP );
+ tags.add( 0, BOLD_END_MARKUP );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ write( MONOSPACED_START_MARKUP );
+ tags.add( 0, MONOSPACED_END_MARKUP );
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ if ( !headFlag )
+ {
+ for ( String tag: inlineStack.pop() )
+ {
+ write( tag );
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
public void italic()
{
- write( ITALIC_START_MARKUP );
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/** {@inheritDoc} */
public void italic_()
{
- write( ITALIC_END_MARKUP );
+ inline_();
}
/** {@inheritDoc} */
@@ -510,14 +568,14 @@
public void monospaced()
{
monospacedFlag = true;
- write( MONOSPACED_START_MARKUP );
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/** {@inheritDoc} */
public void monospaced_()
{
monospacedFlag = false;
- write( MONOSPACED_END_MARKUP );
+ inline_();
}
/**
diff --git a/doxia-modules/doxia-module-confluence/src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceSinkTest.java b/doxia-modules/doxia-module-confluence/src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceSinkTest.java
index 6ca360d..5e75bc1 100644
--- a/doxia-modules/doxia-module-confluence/src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceSinkTest.java
+++ b/doxia-modules/doxia-module-confluence/src/test/java/org/apache/maven/doxia/module/confluence/ConfluenceSinkTest.java
@@ -53,6 +53,19 @@
return false;
}
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return text;
+ }
+
+ /** Not used.
+ * {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getAuthorBlock( String author )
@@ -60,6 +73,12 @@
return null;
}
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return text;
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getBodyBlock()
@@ -75,6 +94,13 @@
/** Not used.
* {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** Not used.
+ * {@inheritDoc} */
protected String getDateBlock( String date )
{
return null;
@@ -87,6 +113,12 @@
}
/** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getFigureBlock( String source, String caption )
{
String figureBlock = EOL + ConfluenceMarkup.FIGURE_START_MARKUP + source + ConfluenceMarkup.FIGURE_END_MARKUP;
@@ -111,6 +143,30 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return ConfluenceMarkup.BOLD_START_MARKUP + text + ConfluenceMarkup.BOLD_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return ConfluenceMarkup.MONOSPACED_START_MARKUP + text + ConfluenceMarkup.MONOSPACED_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return ConfluenceMarkup.ITALIC_START_MARKUP + text + ConfluenceMarkup.ITALIC_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return ConfluenceMarkup.ITALIC_START_MARKUP + text + ConfluenceMarkup.ITALIC_END_MARKUP;
@@ -123,6 +179,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getLinkBlock( String link, String text )
{
return ConfluenceMarkup.LINK_START_MARKUP + text + ConfluenceMarkup.LINK_MIDDLE_MARKUP + link
@@ -141,6 +203,13 @@
return ConfluenceMarkup.MONOSPACED_START_MARKUP + text + ConfluenceMarkup.MONOSPACED_END_MARKUP;
}
+ /** Not used.
+ * {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
/** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
@@ -165,6 +234,19 @@
return text + EOL + EOL;
}
+ /** Not used.
+ * {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
/** {@inheritDoc} */
protected String getRawTextBlock( String text )
{
@@ -207,6 +289,27 @@
return title;
}
+ /** Not used.
+ * {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** Not used.
+ * {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** Not used.
+ * {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
/** {@inheritDoc} */
protected String getTableBlock( String cell, String caption )
{
diff --git a/doxia-modules/doxia-module-docbook-simple/src/main/java/org/apache/maven/doxia/module/docbook/DocBookSink.java b/doxia-modules/doxia-module-docbook-simple/src/main/java/org/apache/maven/doxia/module/docbook/DocBookSink.java
index 00991e4..da91a8e 100644
--- a/doxia-modules/doxia-module-docbook-simple/src/main/java/org/apache/maven/doxia/module/docbook/DocBookSink.java
+++ b/doxia-modules/doxia-module-docbook-simple/src/main/java/org/apache/maven/doxia/module/docbook/DocBookSink.java
@@ -22,22 +22,25 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
+import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractXmlSink;
-import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.apache.maven.doxia.util.DoxiaUtils;
import org.apache.maven.doxia.util.HtmlTools;
-
import org.codehaus.plexus.util.FileUtils;
/**
@@ -150,6 +153,9 @@
private String encoding;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<String>> inlineStack = new Stack<List<String>>();
+
/** Map of warn messages with a String as key to describe the error type and a Set as value.
* Using to reduce warn messages. */
private Map<String, Set<String>> warnMessages;
@@ -683,6 +689,24 @@
/**
* {@inheritDoc}
+ * @see SimplifiedDocbookMarkup#SIDEBAR_TAG
+ */
+ public void sidebar()
+ {
+ writeStartTag( SimplifiedDocbookMarkup.SIDEBAR_TAG );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see SimplifiedDocbookMarkup#SIDEBAR_TAG
+ */
+ public void sidebar_()
+ {
+ writeEndTag( SimplifiedDocbookMarkup.SIDEBAR_TAG );
+ }
+
+ /**
+ * {@inheritDoc}
* @see SimplifiedDocbookMarkup#SECTION_TAG
*/
public void section1()
@@ -881,6 +905,24 @@
/**
* {@inheritDoc}
+ * @see SimplifiedDocbookMarkup#SECTIONINFO_TAG
+ */
+ public void header()
+ {
+ writeStartTag( SimplifiedDocbookMarkup.SECTIONINFO_TAG );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see SimplifiedDocbookMarkup#SECTIONINFO_TAG
+ */
+ public void header_()
+ {
+ writeEndTag( SimplifiedDocbookMarkup.SECTIONINFO_TAG );
+ }
+
+ /**
+ * {@inheritDoc}
* @see SimplifiedDocbookMarkup#ITEMIZEDLIST_TAG
*/
public void list()
@@ -1494,45 +1536,88 @@
}
/** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ List<String> tags = new ArrayList<String>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ markup( italicBeginTag );
+ tags.add( 0, italicEndTag );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ write( boldBeginTag );
+ tags.add( 0, boldEndTag );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ if ( !authorDateFlag )
+ {
+ write( monospacedBeginTag );
+ tags.add( 0, monospacedEndTag );
+ }
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ for ( String tag: inlineStack.pop() )
+ {
+ markup( tag );
+ }
+ }
+
+ /** {@inheritDoc} */
public void italic()
{
- markup( italicBeginTag );
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/** {@inheritDoc} */
public void italic_()
{
- markup( italicEndTag );
+ inline_();
}
/** {@inheritDoc} */
public void bold()
{
- markup( boldBeginTag );
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void bold_()
{
- markup( boldEndTag );
+ inline_();
}
/** {@inheritDoc} */
public void monospaced()
{
- if ( !authorDateFlag )
- {
- markup( monospacedBeginTag );
- }
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/** {@inheritDoc} */
public void monospaced_()
{
- if ( !authorDateFlag )
- {
- markup( monospacedEndTag );
- }
+ inline_();
}
/** {@inheritDoc} */
diff --git a/doxia-modules/doxia-module-docbook-simple/src/test/java/org/apache/maven/doxia/module/docbook/DocBookSinkTest.java b/doxia-modules/doxia-module-docbook-simple/src/test/java/org/apache/maven/doxia/module/docbook/DocBookSinkTest.java
index 20b86cc..c862f3d 100644
--- a/doxia-modules/doxia-module-docbook-simple/src/test/java/org/apache/maven/doxia/module/docbook/DocBookSinkTest.java
+++ b/doxia-modules/doxia-module-docbook-simple/src/test/java/org/apache/maven/doxia/module/docbook/DocBookSinkTest.java
@@ -20,7 +20,6 @@
*/
import java.io.Writer;
-
import java.util.Locale;
import javax.swing.text.MutableAttributeSet;
@@ -30,7 +29,6 @@
import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
import org.apache.maven.doxia.sink.impl.SinkUtils;
import org.apache.maven.doxia.util.DoxiaUtils;
-
import org.codehaus.plexus.util.FileUtils;
/**
@@ -90,6 +88,24 @@
}
/** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "<sidebar></sidebar>";
+ }
+
+ /** {@inheritDoc} */
protected String getSectionTitleBlock( String title )
{
return "<title>" + title + "</title>";
@@ -98,31 +114,49 @@
/** {@inheritDoc} */
protected String getSection1Block( String title )
{
- return "<section><title>" + title + "</title>" + "</section>";
+ return "<section><sectioninfo><title>" + title + "</title></sectioninfo></section>";
}
/** {@inheritDoc} */
protected String getSection2Block( String title )
{
- return "<section><title>" + title + "</title>" + "</section>";
+ return "<section><sectioninfo><title>" + title + "</title></sectioninfo></section>";
}
/** {@inheritDoc} */
protected String getSection3Block( String title )
{
- return "<section><title>" + title + "</title>" + "</section>";
+ return "<section><sectioninfo><title>" + title + "</title></sectioninfo></section>";
}
/** {@inheritDoc} */
protected String getSection4Block( String title )
{
- return "<section><title>" + title + "</title>" + "</section>";
+ return "<section><sectioninfo><title>" + title + "</title></sectioninfo></section>";
}
/** {@inheritDoc} */
protected String getSection5Block( String title )
{
- return "<section><title>" + title + "</title>" + "</section>";
+ return "<section><sectioninfo><title>" + title + "</title></sectioninfo></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "<sectioninfo></sectioninfo>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
}
/** {@inheritDoc} */
@@ -183,6 +217,36 @@
}
/** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getVerbatimBlock( String text )
{
return "<programlisting>" + text + "</programlisting>";
@@ -214,6 +278,30 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return "<emphasis>" + text + "</emphasis>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return "<emphasis role=\"bold\">" + text + "</emphasis>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return "<literal>" + text + "</literal>";
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return "<emphasis>" + text + "</emphasis>";
@@ -238,6 +326,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return " ";
diff --git a/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlContentParser.java b/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlContentParser.java
index ee1478b..a268d36 100644
--- a/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlContentParser.java
+++ b/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlContentParser.java
@@ -20,7 +20,7 @@
*/
import org.apache.maven.doxia.macro.MacroExecutionException;
-import org.apache.maven.doxia.parser.XhtmlBaseParser;
+import org.apache.maven.doxia.parser.Xhtml5BaseParser;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.codehaus.plexus.util.xml.pull.XmlPullParser;
@@ -34,7 +34,7 @@
* @since 1.0
*/
public class FmlContentParser
- extends XhtmlBaseParser
+ extends Xhtml5BaseParser
implements FmlMarkup
{
/** Empty elements don't write a closing tag. */
diff --git a/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlParser.java b/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlParser.java
index d617321..c2a296e 100644
--- a/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlParser.java
+++ b/doxia-modules/doxia-module-fml/src/main/java/org/apache/maven/doxia/module/fml/FmlParser.java
@@ -23,7 +23,6 @@
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
-
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -46,7 +45,6 @@
import org.apache.maven.doxia.sink.impl.XhtmlBaseSink;
import org.apache.maven.doxia.util.DoxiaUtils;
import org.apache.maven.doxia.util.HtmlTools;
-
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
@@ -583,9 +581,9 @@
if ( StringUtils.isNotEmpty( part.getTitle() ) )
{
sink.paragraph();
- sink.bold();
+ sink.inline( SinkEventAttributeSet.Semantics.BOLD );
xdocParser.parse( part.getTitle(), sink );
- sink.bold_();
+ sink.inline_();
sink.paragraph_();
}
diff --git a/doxia-modules/doxia-module-fml/src/test/java/org/apache/maven/doxia/module/fml/FmlParserTest.java b/doxia-modules/doxia-module-fml/src/test/java/org/apache/maven/doxia/module/fml/FmlParserTest.java
index c2991db..176650c 100644
--- a/doxia-modules/doxia-module-fml/src/test/java/org/apache/maven/doxia/module/fml/FmlParserTest.java
+++ b/doxia-modules/doxia-module-fml/src/test/java/org/apache/maven/doxia/module/fml/FmlParserTest.java
@@ -123,9 +123,9 @@
assertEquals( "anchor_", ( it.next() ).getName() );
assertEquals( "sectionTitle1_", ( it.next() ).getName() );
assertEquals( "paragraph", ( it.next() ).getName() );
- assertEquals( "bold", ( it.next() ).getName() );
+ assertEquals( "inline", ( it.next() ).getName() );
assertEquals( "text", ( it.next() ).getName() );
- assertEquals( "bold_", ( it.next() ).getName() );
+ assertEquals( "inline_", ( it.next() ).getName() );
assertEquals( "paragraph_", ( it.next() ).getName() );
assertEquals( "numberedList", ( it.next() ).getName() );
assertEquals( "numberedListItem", ( it.next() ).getName() );
@@ -197,13 +197,13 @@
assertEquals( "anchor_", ( it.next() ).getName() );
assertEquals( "sectionTitle1_", ( it.next() ).getName() );
assertEquals( "paragraph", ( it.next() ).getName() );
- assertEquals( "bold", ( it.next() ).getName() );
+ assertEquals( "inline", ( it.next() ).getName() );
// part title in TOC
assertTextEvent( it.next(), "<" );
assertTextEvent( it.next(), "\u0391" );
- assertEquals( "bold_", ( it.next() ).getName() );
+ assertEquals( "inline_", ( it.next() ).getName() );
assertEquals( "paragraph_", ( it.next() ).getName() );
assertEquals( "numberedList", ( it.next() ).getName() );
assertEquals( "numberedListItem", ( it.next() ).getName() );
@@ -239,11 +239,11 @@
assertEquals( "paragraph", ( it.next() ).getName() );
// answer
- assertEquals( "monospaced", ( it.next() ).getName() );
+ assertEquals( "inline", ( it.next() ).getName() );
assertTextEvent( it.next(), "<" );
assertTextEvent( it.next(), "img" );
assertTextEvent( it.next(), ">" );
- assertEquals( "monospaced_", ( it.next() ).getName() );
+ assertEquals( "inline_", ( it.next() ).getName() );
assertTextEvent( it.next(), "\"" );
assertTextEvent( it.next(), "\u0391" );
diff --git a/doxia-modules/doxia-module-fo/src/main/java/org/apache/maven/doxia/module/fo/FoSink.java b/doxia-modules/doxia-module-fo/src/main/java/org/apache/maven/doxia/module/fo/FoSink.java
index da6c6c7..2a448a3 100644
--- a/doxia-modules/doxia-module-fo/src/main/java/org/apache/maven/doxia/module/fo/FoSink.java
+++ b/doxia-modules/doxia-module-fo/src/main/java/org/apache/maven/doxia/module/fo/FoSink.java
@@ -24,9 +24,11 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
@@ -113,6 +115,9 @@
/** The stack of table caption */
private final LinkedList<String> tableCaptionStack;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<Tag>> inlineStack = new Stack<List<Tag>>();
+
/** Map of warn messages with a String as key to describe the error type and a Set as value.
* Using to reduce warn messages. */
protected Map<String, Set<String>> warnMessages;
@@ -1253,39 +1258,85 @@
}
/** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ List<Tag> tags = new ArrayList<Tag>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ writeStartTag( INLINE_TAG, "italic" );
+ tags.add( 0, INLINE_TAG );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ writeStartTag( INLINE_TAG, "bold" );
+ tags.add( 0, INLINE_TAG );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ writeStartTag( INLINE_TAG, "monospace" );
+ tags.add( 0, INLINE_TAG );
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ for ( Tag tag: inlineStack.pop() )
+ {
+ writeEndTag( tag );
+ }
+ }
+
+ /** {@inheritDoc} */
public void italic()
{
- writeStartTag( INLINE_TAG, "italic" );
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/** {@inheritDoc} */
public void italic_()
{
- writeEndTag( INLINE_TAG );
+ inline_();
}
/** {@inheritDoc} */
public void bold()
{
- writeStartTag( INLINE_TAG, "bold" );
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void bold_()
{
- writeEndTag( INLINE_TAG );
+ inline_();
}
/** {@inheritDoc} */
public void monospaced()
{
- writeStartTag( INLINE_TAG, "monospace" );
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/** {@inheritDoc} */
public void monospaced_()
{
- writeEndTag( INLINE_TAG );
+ inline_();
}
/** {@inheritDoc} */
diff --git a/doxia-modules/doxia-module-fo/src/test/java/org/apache/maven/doxia/module/fo/FoSinkTest.java b/doxia-modules/doxia-module-fo/src/test/java/org/apache/maven/doxia/module/fo/FoSinkTest.java
index 70ce09e..7d78aca 100644
--- a/doxia-modules/doxia-module-fo/src/test/java/org/apache/maven/doxia/module/fo/FoSinkTest.java
+++ b/doxia-modules/doxia-module-fo/src/test/java/org/apache/maven/doxia/module/fo/FoSinkTest.java
@@ -199,6 +199,21 @@
return EOL + "</fo:flow>" + EOL + "</fo:page-sequence>" + EOL + "</fo:root>" + EOL;
}
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
/** {@inheritDoc} */
protected String getSectionTitleBlock( String title )
{
@@ -250,6 +265,22 @@
+ "</fo:block>" + EOL + "</fo:block>" + EOL;
}
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
/** {@inheritDoc} */
protected String getListBlock( String item )
{
@@ -332,6 +363,36 @@
}
/** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getVerbatimBlock( String text )
{
String attribs = getConfig().getAttributeString( "body.source" );
@@ -367,6 +428,33 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ String attribs = getConfig().getAttributeString( "italic" );
+ return EOL + "<fo:inline" + attribs + ">" + text + "</fo:inline>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ String attribs = getConfig().getAttributeString( "bold" );
+ return EOL + "<fo:inline" + attribs + ">" + text + "</fo:inline>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ String attribs = getConfig().getAttributeString( "monospace" );
+ return EOL + "<fo:inline" + attribs + ">" + text + "</fo:inline>";
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
String attribs = getConfig().getAttributeString( "italic" );
@@ -394,6 +482,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return " ";
diff --git a/doxia-modules/doxia-module-itext/src/main/java/org/apache/maven/doxia/module/itext/ITextSink.java b/doxia-modules/doxia-module-itext/src/main/java/org/apache/maven/doxia/module/itext/ITextSink.java
index 76b788a..7dd32ec 100644
--- a/doxia-modules/doxia-module-itext/src/main/java/org/apache/maven/doxia/module/itext/ITextSink.java
+++ b/doxia-modules/doxia-module-itext/src/main/java/org/apache/maven/doxia/module/itext/ITextSink.java
@@ -32,15 +32,19 @@
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.Stack;
import java.util.TreeSet;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractXmlSink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.apache.maven.doxia.util.DoxiaUtils;
import org.apache.maven.doxia.util.HtmlTools;
@@ -118,6 +122,9 @@
/** Flag to know if an figure event is called. */
private boolean figureDefined = false;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<String>> inlineStack = new Stack<List<String>>();
+
/** Map of warn messages with a String as key to describe the error type and a Set as value.
* Using to reduce warn messages. */
private Map<String, Set<String>> warnMessages;
@@ -1268,39 +1275,96 @@
// ----------------------------------------------------------------------
/** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ List<String> tags = new ArrayList<String>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ font.addItalic();
+ tags.add( 0, "italic" );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ font.addBold();
+ tags.add( 0, "bold" );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ font.setMonoSpaced( true );
+ tags.add( 0, "code" );
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ for ( String tag: inlineStack.pop() )
+ {
+ if ( "italic".equals( tag ) )
+ {
+ font.removeItalic();
+ }
+ else if ( "bold".equals( tag ) )
+ {
+ font.removeBold();
+ }
+ else if ( "code".equals( tag ) )
+ {
+ font.setMonoSpaced( false );
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
public void bold_()
{
- font.removeBold();
+ inline_();
}
/** {@inheritDoc} */
public void bold()
{
- font.addBold();
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void italic_()
{
- font.removeItalic();
+ inline_();
}
/** {@inheritDoc} */
public void italic()
{
- font.addItalic();
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/** {@inheritDoc} */
public void monospaced_()
{
- font.setMonoSpaced( false );
+ inline_();
}
/** {@inheritDoc} */
public void monospaced()
{
- font.setMonoSpaced( true );
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
// ----------------------------------------------------------------------
diff --git a/doxia-modules/doxia-module-latex/src/main/java/org/apache/maven/doxia/module/latex/LatexSink.java b/doxia-modules/doxia-module-latex/src/main/java/org/apache/maven/doxia/module/latex/LatexSink.java
index 0bce451..9566af4 100644
--- a/doxia-modules/doxia-module-latex/src/main/java/org/apache/maven/doxia/module/latex/LatexSink.java
+++ b/doxia-modules/doxia-module-latex/src/main/java/org/apache/maven/doxia/module/latex/LatexSink.java
@@ -32,7 +32,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
+import java.util.Stack;
/**
* Latex Sink implementation.
@@ -80,6 +83,9 @@
private String title;
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<String>> inlineStack = new Stack<List<String>>();
+
// ----------------------------------------------------------------------
//
// ----------------------------------------------------------------------
@@ -1126,12 +1132,58 @@
markup( "}" );
}
+ /** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ List<String> tags = new ArrayList<String>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ markup( "\\textit{" );
+ tags.add( 0, "}" );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ markup( "\\textbf{" );
+ tags.add( 0, "}" );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ markup( "\\texttt{\\small " );
+ tags.add( 0, "}" );
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ for ( String tag: inlineStack.pop() )
+ {
+ markup( tag );
+ }
+ }
+
/**
* {@inheritDoc}
*/
public void italic()
{
- markup( "\\textit{" );
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/**
@@ -1139,7 +1191,7 @@
*/
public void italic_()
{
- markup( "}" );
+ inline_();
}
/**
@@ -1147,7 +1199,7 @@
*/
public void bold()
{
- markup( "\\textbf{" );
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/**
@@ -1155,7 +1207,7 @@
*/
public void bold_()
{
- markup( "}" );
+ inline_();
}
/**
@@ -1163,7 +1215,7 @@
*/
public void monospaced()
{
- markup( "\\texttt{\\small " );
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/**
@@ -1171,7 +1223,7 @@
*/
public void monospaced_()
{
- markup( "}" );
+ inline_();
}
/**
diff --git a/doxia-modules/doxia-module-latex/src/test/java/org/apache/maven/doxia/module/latex/LatexSinkTest.java b/doxia-modules/doxia-module-latex/src/test/java/org/apache/maven/doxia/module/latex/LatexSinkTest.java
index e2f0e68..dc259a5 100644
--- a/doxia-modules/doxia-module-latex/src/test/java/org/apache/maven/doxia/module/latex/LatexSinkTest.java
+++ b/doxia-modules/doxia-module-latex/src/test/java/org/apache/maven/doxia/module/latex/LatexSinkTest.java
@@ -83,6 +83,24 @@
}
/** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getSectionTitleBlock( String title )
{
return title;
@@ -119,6 +137,24 @@
}
/** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getListBlock( String item )
{
return EOL + "\\begin{itemize}" + EOL + "\\item " + LatexSink.escaped( item ) + EOL + "\\end{itemize}" + EOL;
@@ -166,6 +202,36 @@
}
/** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getVerbatimBlock( String text )
{
return EOL + "\\begin{small}" + EOL + "\\begin{Verbatim}[frame=single]" + EOL + text + EOL
@@ -197,6 +263,30 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return "\\textit{" + text + "}";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return "\\textbf{" + text + "}";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return "\\texttt{\\small " + text + "}";
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return "\\textit{" + text + "}";
@@ -221,6 +311,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return "~";
diff --git a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java
index 2f99bc9..b1fb22c 100644
--- a/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java
+++ b/doxia-modules/doxia-module-markdown/src/test/java/org/apache/maven/doxia/module/markdown/MarkdownParserTest.java
@@ -101,7 +101,7 @@
{
Iterator<SinkEventElement> it = parseFileToEventTestingSink( "bold" ).getEventList().iterator();
- assertEquals( it, "head", "head_", "body", "paragraph", "bold", "text", "bold_", "paragraph_", "body_" );
+ assertEquals( it, "head", "head_", "body", "paragraph", "inline", "text", "inline_", "paragraph_", "body_" );
assertFalse( it.hasNext() );
}
@@ -116,7 +116,7 @@
{
Iterator<SinkEventElement> it = parseFileToEventTestingSink( "italic" ).getEventList().iterator();
- assertEquals( it, "head", "head_", "body", "paragraph", "italic", "text", "italic_", "paragraph_", "body_" );
+ assertEquals( it, "head", "head_", "body", "paragraph", "inline", "text", "inline_", "paragraph_", "body_" );
assertFalse( it.hasNext() );
}
@@ -290,8 +290,8 @@
Iterator<SinkEventElement> it = parseFileToEventTestingSink( "html-content" ).getEventList().iterator();
// NOTE: H1 and DIV are rendered as "unknown" and H2 is "section1" (see DOXIA-203)
- assertEquals( it, "head", "head_", "body", "unknown", "text", "paragraph", "bold", "text",
- "bold_", "text", "bold", "text", "bold_", "text", "paragraph_", "text", "unknown", "text", "horizontalRule", "unknown",
+ assertEquals( it, "head", "head_", "body", "unknown", "text", "paragraph", "inline", "text",
+ "inline_", "text", "inline", "text", "inline_", "text", "paragraph_", "text", "unknown", "text", "horizontalRule", "unknown",
"text", "unknown", "paragraph", "text", "paragraph_", "text", "table", "tableRows", "text", "tableRow",
"tableHeaderCell", "text", "tableHeaderCell_", "tableRow_", "text", "tableRow",
"tableCell", "text", "tableCell_", "tableRow_", "text", "tableRows_", "table_",
diff --git a/doxia-modules/doxia-module-rtf/src/main/java/org/apache/maven/doxia/module/rtf/RtfSink.java b/doxia-modules/doxia-module-rtf/src/main/java/org/apache/maven/doxia/module/rtf/RtfSink.java
index 8809fa0..24da5ba 100644
--- a/doxia-modules/doxia-module-rtf/src/main/java/org/apache/maven/doxia/module/rtf/RtfSink.java
+++ b/doxia-modules/doxia-module-rtf/src/main/java/org/apache/maven/doxia/module/rtf/RtfSink.java
@@ -20,7 +20,6 @@
*/
import java.awt.Color;
-
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
@@ -28,12 +27,14 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
-
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.Vector;
@@ -41,6 +42,7 @@
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.SinkEventAttributes;
import org.apache.maven.doxia.sink.impl.AbstractTextSink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
/**
* <a href="http://en.wikipedia.org/wiki/Rich_Text_Format">RTF</a> Sink implementation.
@@ -215,6 +217,9 @@
protected OutputStream stream; // for raw image data
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<Integer>> inlineStack = new Stack<List<Integer>>();
+
/** Map of warn messages with a String as key to describe the error type and a Set as value.
* Using to reduce warn messages. */
private Map warnMessages;
@@ -1445,39 +1450,86 @@
}
/** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ List<Integer> tags = new ArrayList<Integer>();
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ tags.add( 0, this.style );
+ beginStyle( STYLE_ITALIC );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ tags.add( 0, this.style );
+ beginStyle( STYLE_BOLD );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ tags.add( 0, this.style );
+ beginStyle( STYLE_TYPEWRITER );
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ for ( Integer style: inlineStack.pop() )
+ {
+ endStyle();
+ this.style = style;
+ }
+ }
+
+ /** {@inheritDoc} */
public void italic()
{
- beginStyle( STYLE_ITALIC );
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/** {@inheritDoc} */
public void italic_()
{
- endStyle();
+ inline_();
}
/** {@inheritDoc} */
public void bold()
{
- beginStyle( STYLE_BOLD );
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void bold_()
{
- endStyle();
+ inline_();
}
/** {@inheritDoc} */
public void monospaced()
{
- beginStyle( STYLE_TYPEWRITER );
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/** {@inheritDoc} */
public void monospaced_()
{
- endStyle();
+ inline_();
}
private void beginStyle( int style )
diff --git a/doxia-modules/doxia-module-twiki/src/main/java/org/apache/maven/doxia/module/twiki/TWikiSink.java b/doxia-modules/doxia-module-twiki/src/main/java/org/apache/maven/doxia/module/twiki/TWikiSink.java
index a125716..dffbcb6 100644
--- a/doxia-modules/doxia-module-twiki/src/main/java/org/apache/maven/doxia/module/twiki/TWikiSink.java
+++ b/doxia-modules/doxia-module-twiki/src/main/java/org/apache/maven/doxia/module/twiki/TWikiSink.java
@@ -22,6 +22,8 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Stack;
import javax.swing.text.MutableAttributeSet;
@@ -57,9 +59,6 @@
/** An indication on if we're in bold mode. */
private boolean boldFlag;
- /** An indication on if we're in bold italic or monospaced mode. */
- private boolean boldItalicOrMonodpacedFlag;
-
/** An indication on if we're in head mode. */
private boolean headFlag;
@@ -68,6 +67,12 @@
/** listStyles. */
private final Stack<String> listStyles;
+ /** Keep track of the nested bold flag. */
+ protected Stack<Boolean> boldStack = new Stack<Boolean>();
+
+ /** Keep track of the closing tags for inline events. */
+ protected Stack<List<String>> inlineStack = new Stack<List<String>>();
+
/**
* Constructor, initialize the Writer and the variables.
*
@@ -155,19 +160,13 @@
/** {@inheritDoc} */
public void bold()
{
- boldFlag = true;
- write( BOLD_START_MARKUP );
+ inline( SinkEventAttributeSet.Semantics.BOLD );
}
/** {@inheritDoc} */
public void bold_()
{
- boldFlag = false;
- if ( !boldItalicOrMonodpacedFlag )
- {
- write( BOLD_END_MARKUP );
- }
- boldItalicOrMonodpacedFlag = false;
+ inline_();
}
/**
@@ -398,34 +397,87 @@
}
/** {@inheritDoc} */
+ public void inline()
+ {
+ inline( null );
+ }
+
+ /** {@inheritDoc} */
+ public void inline( SinkEventAttributes attributes )
+ {
+ List<String> tags = new ArrayList<String>();
+
+ boldStack.push( boldFlag );
+
+ if ( attributes != null )
+ {
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
+ {
+ boldFlag = true;
+ write( BOLD_START_MARKUP );
+ tags.add( 0, BOLD_END_MARKUP );
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
+ {
+ if ( boldFlag )
+ {
+ String tmp = writer.toString();
+ writer = new StringWriter();
+ writer.write( tmp.substring( 0, tmp.length() - 1 ) );
+ write( BOLD_ITALIC_START_MARKUP );
+ tags.add( 0, BOLD_ITALIC_END_MARKUP );
+ }
+ else
+ {
+ write( ITALIC_START_MARKUP );
+ tags.add( ITALIC_END_MARKUP );
+ }
+ }
+
+ if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
+ {
+ if ( boldFlag )
+ {
+ String tmp = writer.toString();
+ writer = new StringWriter();
+ writer.write( tmp.substring( 0, tmp.length() - 1 ) );
+ write( BOLD_MONOSPACED_START_MARKUP );
+ tags.add( 0, BOLD_MONOSPACED_END_MARKUP );
+ }
+ else
+ {
+ write( MONOSPACED_START_MARKUP );
+ tags.add( 0, MONOSPACED_END_MARKUP );
+ }
+ }
+
+ }
+
+ inlineStack.push( tags );
+ }
+
+ /** {@inheritDoc} */
+ public void inline_()
+ {
+ for ( String tag: inlineStack.pop() )
+ {
+ write( tag );
+ }
+ this.boldFlag = boldStack.pop();
+ }
+
+ /** {@inheritDoc} */
public void italic()
{
- if ( boldFlag )
- {
- boldItalicOrMonodpacedFlag = true;
-
- String tmp = writer.toString();
- writer = new StringWriter();
- writer.write( tmp.substring( 0, tmp.length() - 1 ) );
- write( BOLD_ITALIC_START_MARKUP );
- }
- else
- {
- write( ITALIC_START_MARKUP );
- }
+ inline( SinkEventAttributeSet.Semantics.ITALIC );
}
/** {@inheritDoc} */
public void italic_()
{
- if ( boldFlag )
- {
- write( BOLD_ITALIC_END_MARKUP );
- }
- else
- {
- write( ITALIC_END_MARKUP );
- }
+ inline_();
}
/**
@@ -506,32 +558,13 @@
/** {@inheritDoc} */
public void monospaced()
{
- if ( boldFlag )
- {
- boldItalicOrMonodpacedFlag = true;
-
- String tmp = writer.toString();
- writer = new StringWriter();
- writer.write( tmp.substring( 0, tmp.length() - 1 ) );
- write( BOLD_MONOSPACED_START_MARKUP );
- }
- else
- {
- write( MONOSPACED_START_MARKUP );
- }
+ inline( SinkEventAttributeSet.Semantics.CODE );
}
/** {@inheritDoc} */
public void monospaced_()
{
- if ( boldFlag )
- {
- write( BOLD_MONOSPACED_END_MARKUP );
- }
- else
- {
- write( MONOSPACED_END_MARKUP );
- }
+ inline_();
}
/**
@@ -1277,7 +1310,6 @@
this.levelList = 0;
this.listStyles.clear();
this.boldFlag = false;
- this.boldItalicOrMonodpacedFlag = false;
}
/**
diff --git a/doxia-modules/doxia-module-twiki/src/test/java/org/apache/maven/doxia/module/twiki/TWikiSinkTest.java b/doxia-modules/doxia-module-twiki/src/test/java/org/apache/maven/doxia/module/twiki/TWikiSinkTest.java
index 378ea8b..815ce1a 100644
--- a/doxia-modules/doxia-module-twiki/src/test/java/org/apache/maven/doxia/module/twiki/TWikiSinkTest.java
+++ b/doxia-modules/doxia-module-twiki/src/test/java/org/apache/maven/doxia/module/twiki/TWikiSinkTest.java
@@ -49,11 +49,23 @@
}
/** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getAnchorBlock( String anchor )
{
return EOL + "#" + anchor + anchor;
}
+ /** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getAuthorBlock( String author )
@@ -61,6 +73,12 @@
return null;
}
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return text;
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getBodyBlock()
@@ -74,6 +92,18 @@
return TWikiMarkup.BOLD_START_MARKUP + text + TWikiMarkup.BOLD_END_MARKUP;
}
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getDateBlock( String date )
@@ -89,6 +119,12 @@
}
/** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
protected String getFigureBlock( String source, String caption )
{
String figureBlock = "<img src=\"" + source + "\"";
@@ -100,6 +136,12 @@
return figureBlock;
}
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getHeadBlock()
@@ -108,12 +150,42 @@
}
/** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getHorizontalRuleBlock()
{
return TWikiMarkup.HORIZONTAL_RULE_MARKUP + EOL;
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return TWikiMarkup.ITALIC_START_MARKUP + text + TWikiMarkup.ITALIC_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return TWikiMarkup.BOLD_START_MARKUP + text + TWikiMarkup.BOLD_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return TWikiMarkup.MONOSPACED_START_MARKUP + text + TWikiMarkup.MONOSPACED_END_MARKUP;
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return TWikiMarkup.ITALIC_START_MARKUP + text + TWikiMarkup.ITALIC_END_MARKUP;
@@ -126,6 +198,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getLinkBlock( String link, String text )
{
return TWikiMarkup.LINK_START_MARKUP + link + TWikiMarkup.LINK_MIDDLE_MARKUP + text
@@ -145,6 +223,12 @@
}
/** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return "";
@@ -211,6 +295,12 @@
}
/** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getTableBlock( String cell, String caption )
{
return "| " + cell + " |" + EOL + "Table_caption";
@@ -222,6 +312,12 @@
return HtmlTools.escapeHTML( text );
}
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
/** Not used.
* {@inheritDoc} */
protected String getTitleBlock( String title )
diff --git a/doxia-modules/doxia-module-xdoc/src/main/java/org/apache/maven/doxia/module/xdoc/XdocParser.java b/doxia-modules/doxia-module-xdoc/src/main/java/org/apache/maven/doxia/module/xdoc/XdocParser.java
index 9740eff..32f062f 100644
--- a/doxia-modules/doxia-module-xdoc/src/main/java/org/apache/maven/doxia/module/xdoc/XdocParser.java
+++ b/doxia-modules/doxia-module-xdoc/src/main/java/org/apache/maven/doxia/module/xdoc/XdocParser.java
@@ -29,15 +29,14 @@
import javax.swing.text.html.HTML.Attribute;
import org.apache.maven.doxia.macro.MacroExecutionException;
-import org.apache.maven.doxia.macro.manager.MacroNotFoundException;
import org.apache.maven.doxia.macro.MacroRequest;
+import org.apache.maven.doxia.macro.manager.MacroNotFoundException;
import org.apache.maven.doxia.parser.ParseException;
import org.apache.maven.doxia.parser.Parser;
import org.apache.maven.doxia.parser.XhtmlBaseParser;
import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
import org.apache.maven.doxia.util.HtmlTools;
-
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
diff --git a/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java b/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java
index fe85246..ae2fba5 100644
--- a/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java
+++ b/doxia-modules/doxia-module-xdoc/src/test/java/org/apache/maven/doxia/module/xdoc/XdocSinkTest.java
@@ -88,6 +88,24 @@
}
/** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getSectionTitleBlock( String title )
{
return title;
@@ -124,6 +142,24 @@
}
/** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getListBlock( String item )
{
return "<ul>\n<li>" + item + "</li></ul>";
@@ -171,6 +207,36 @@
}
/** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return "<address>" + text + "</address>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return "<blockquote>" + text + "</blockquote>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return "<div>" + text + "</div>";
+ }
+
+ /** {@inheritDoc} */
protected String getVerbatimBlock( String text )
{
return "<source>" + text + "</source>";
@@ -201,6 +267,30 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return "<i>" + text + "</i>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return "<b>" + text + "</b>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return "<code>" + text + "</code>";
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return "<i>" + text + "</i>";
@@ -225,6 +315,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return " ";
diff --git a/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java b/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java
index dceb4f0..fe1a814 100644
--- a/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java
+++ b/doxia-modules/doxia-module-xhtml/src/main/java/org/apache/maven/doxia/module/xhtml/XhtmlParser.java
@@ -118,7 +118,7 @@
*/
else if ( parser.getName().equals( ADDRESS.toString() ) )
{
- sink.author( attribs );
+ sink.address( attribs );
}
else if ( parser.getName().equals( BODY.toString() ) )
{
@@ -203,7 +203,7 @@
}
else if ( parser.getName().equals( ADDRESS.toString() ) )
{
- sink.author_();
+ sink.address_();
}
else if ( parser.getName().equals( DIV.toString() ) )
{
diff --git a/doxia-modules/doxia-module-xhtml/src/test/java/org/apache/maven/doxia/module/xhtml/XhtmlSinkTest.java b/doxia-modules/doxia-module-xhtml/src/test/java/org/apache/maven/doxia/module/xhtml/XhtmlSinkTest.java
index ef51427..1bb7507 100644
--- a/doxia-modules/doxia-module-xhtml/src/test/java/org/apache/maven/doxia/module/xhtml/XhtmlSinkTest.java
+++ b/doxia-modules/doxia-module-xhtml/src/test/java/org/apache/maven/doxia/module/xhtml/XhtmlSinkTest.java
@@ -122,6 +122,24 @@
}
/** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getSectionTitleBlock( String title )
{
return title;
@@ -158,6 +176,24 @@
}
/** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getListBlock( String item )
{
return "<ul>\n<li>" + item + "</li></ul>";
@@ -214,6 +250,36 @@
}
/** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return "<address>" + text + "</address>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return "<blockquote>" + text + "</blockquote>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return "<div>" + text + "</div>";
+ }
+
+ /** {@inheritDoc} */
protected String getVerbatimBlock( String text )
{
return "<div class=\"source\">\n<pre>" + text + "</pre></div>";
@@ -244,6 +310,30 @@
}
/** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return "<i>" + text + "</i>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return "<b>" + text + "</b>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return "<code>" + text + "</code>";
+ }
+
+ /** {@inheritDoc} */
protected String getItalicBlock( String text )
{
return "<i>" + text + "</i>";
@@ -268,6 +358,12 @@
}
/** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
protected String getNonBreakingSpaceBlock()
{
return " ";
diff --git a/doxia-modules/doxia-module-xhtml5/pom.xml b/doxia-modules/doxia-module-xhtml5/pom.xml
new file mode 100644
index 0000000..b372b8a
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <artifactId>doxia-modules</artifactId>
+ <groupId>org.apache.maven.doxia</groupId>
+ <version>1.9-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>doxia-module-xhtml5</artifactId>
+
+ <name>Doxia :: XHTML5 Module</name>
+ <description>
+ A Doxia module for Xhtml5 source documents.
+ Xhtml5 format is supported both as source and target formats.
+ </description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.xmlunit</groupId>
+ <artifactId>xmlunit-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.xmlunit</groupId>
+ <artifactId>xmlunit-matchers</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/AbstractXhtml5Sink.java b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/AbstractXhtml5Sink.java
new file mode 100644
index 0000000..ab004f6
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/AbstractXhtml5Sink.java
@@ -0,0 +1,30 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.doxia.sink.impl.SinkAdapter;
+
+/**
+ * <p>Abstract AbstractXhtml5Sink class.</p>
+ */
+public abstract class AbstractXhtml5Sink
+ extends SinkAdapter
+{
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Markup.java b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Markup.java
new file mode 100644
index 0000000..bdd4e9f
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Markup.java
@@ -0,0 +1,36 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.doxia.markup.HtmlMarkup;
+
+/**
+ * List of <code>Xhtml</code> markups.
+ * <br>
+ * Xhtml uses all {@link javax.swing.text.html.HTML.Tag} and {@link javax.swing.text.html.HTML.Attribute}
+ * as markups.
+ */
+@SuppressWarnings( "checkstyle:interfaceistype" )
+public interface Xhtml5Markup
+ extends HtmlMarkup
+{
+ /** XHTML5 namespace: "http://www.w3.org/1999/xhtml" */
+ String XHTML5_NAMESPACE = "http://www.w3.org/1999/xhtml";
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Parser.java b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Parser.java
new file mode 100644
index 0000000..fac80bd
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Parser.java
@@ -0,0 +1,364 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.text.html.HTML.Attribute;
+
+import org.apache.maven.doxia.macro.MacroExecutionException;
+import org.apache.maven.doxia.macro.manager.MacroNotFoundException;
+import org.apache.maven.doxia.macro.MacroRequest;
+import org.apache.maven.doxia.parser.ParseException;
+import org.apache.maven.doxia.parser.Parser;
+import org.apache.maven.doxia.parser.Xhtml5BaseParser;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Parse an xhtml model and emit events into a Doxia Sink.
+ */
+@Component( role = Parser.class, hint = "xhtml5" )
+public class Xhtml5Parser
+ extends Xhtml5BaseParser
+ implements Xhtml5Markup
+{
+ /**
+ * The role hint for the {@link Xhtml5Parser} Plexus component.
+ */
+ public static final String ROLE_HINT = "xhtml5";
+
+ /** For boxed verbatim. */
+ private boolean boxed;
+
+ /** Empty elements don't write a closing tag. */
+ private boolean isEmptyElement;
+
+ /**
+ * The source content of the input reader. Used to pass into macros.
+ */
+ private String sourceContent;
+
+ /** {@inheritDoc} */
+ protected void handleStartTag( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException, MacroExecutionException
+ {
+ isEmptyElement = parser.isEmptyElementTag();
+
+ SinkEventAttributeSet attribs = getAttributesFromParser( parser );
+
+ if ( parser.getName().equals( HTML.toString() ) )
+ {
+ //Do nothing
+ return;
+ }
+ else if ( parser.getName().equals( HEAD.toString() ) )
+ {
+ sink.head( attribs );
+ }
+ else if ( parser.getName().equals( TITLE.toString() ) )
+ {
+ sink.title( attribs );
+ }
+ else if ( parser.getName().equals( META.toString() ) )
+ {
+ String name = parser.getAttributeValue( null, Attribute.NAME.toString() );
+ String content = parser.getAttributeValue( null, Attribute.CONTENT.toString() );
+
+ if ( "author".equals( name ) )
+ {
+ sink.author( null );
+
+ sink.text( content );
+
+ sink.author_();
+ }
+ else if ( "date".equals( name ) )
+ {
+ sink.date( null );
+
+ sink.text( content );
+
+ sink.date_();
+ }
+ else
+ {
+ sink.unknown( "meta", new Object[] { Integer.valueOf( TAG_TYPE_SIMPLE ) }, attribs );
+ }
+ }
+ /*
+ * The ADDRESS element may be used by authors to supply contact information
+ * for a model or a major part of a model such as a form. This element
+ * often appears at the beginning or end of a model.
+ */
+ else if ( parser.getName().equals( ADDRESS.toString() ) )
+ {
+ sink.address( attribs );
+ }
+ else if ( parser.getName().equals( BODY.toString() ) )
+ {
+ sink.body( attribs );
+ }
+ else if ( parser.getName().equals( DIV.toString() ) )
+ {
+ String divclass = parser.getAttributeValue( null, Attribute.CLASS.toString() );
+
+ if ( "source".equals( divclass ) )
+ {
+ this.boxed = true;
+ }
+
+ baseStartTag( parser, sink ); // pick up other divs
+ }
+ /*
+ * The PRE element tells visual user agents that the enclosed text is
+ * "preformatted". When handling preformatted text, visual user agents:
+ * - May leave white space intact.
+ * - May render text with a fixed-pitch font.
+ * - May disable automatic word wrap.
+ * - Must not disable bidirectional processing.
+ * Non-visual user agents are not required to respect extra white space
+ * in the content of a PRE element.
+ */
+ else if ( parser.getName().equals( PRE.toString() ) )
+ {
+ if ( boxed )
+ {
+ attribs.addAttributes( SinkEventAttributeSet.BOXED );
+ }
+
+ verbatim();
+
+ sink.verbatim( attribs );
+ }
+ else if ( !baseStartTag( parser, sink ) )
+ {
+ if ( isEmptyElement )
+ {
+ handleUnknown( parser, sink, TAG_TYPE_SIMPLE );
+ }
+ else
+ {
+ handleUnknown( parser, sink, TAG_TYPE_START );
+ }
+
+ if ( getLog().isDebugEnabled() )
+ {
+ String position = "[" + parser.getLineNumber() + ":"
+ + parser.getColumnNumber() + "]";
+ String tag = "<" + parser.getName() + ">";
+
+ getLog().debug( "Unrecognized xhtml5 tag: " + tag + " at " + position );
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void handleEndTag( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException, MacroExecutionException
+ {
+ if ( parser.getName().equals( HTML.toString() ) )
+ {
+ //Do nothing
+ return;
+ }
+ else if ( parser.getName().equals( HEAD.toString() ) )
+ {
+ sink.head_();
+ }
+ else if ( parser.getName().equals( TITLE.toString() ) )
+ {
+ sink.title_();
+ }
+ else if ( parser.getName().equals( BODY.toString() ) )
+ {
+ consecutiveSections( 0, sink, null );
+
+ sink.body_();
+ }
+ else if ( parser.getName().equals( ADDRESS.toString() ) )
+ {
+ sink.address_();
+ }
+ else if ( parser.getName().equals( DIV.toString() ) )
+ {
+ this.boxed = false;
+ baseEndTag( parser, sink );
+ }
+ else if ( !baseEndTag( parser, sink ) )
+ {
+ if ( !isEmptyElement )
+ {
+ handleUnknown( parser, sink, TAG_TYPE_END );
+ }
+ }
+
+ isEmptyElement = false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void handleComment( XmlPullParser parser, Sink sink )
+ throws XmlPullParserException
+ {
+ String text = getText( parser ).trim();
+
+ if ( text.startsWith( "MACRO" ) && !isSecondParsing() )
+ {
+ processMacro( text, sink );
+ }
+ else
+ {
+ super.handleComment( parser, sink );
+ }
+ }
+
+ /** process macro embedded in XHTML commment */
+ private void processMacro( String text, Sink sink )
+ throws XmlPullParserException
+ {
+ String s = text.substring( text.indexOf( '{' ) + 1, text.indexOf( '}' ) );
+ s = escapeForMacro( s );
+ String[] params = StringUtils.split( s, "|" );
+ String macroName = params[0];
+
+ Map<String, Object> parameters = new HashMap<String, Object>();
+ for ( int i = 1; i < params.length; i++ )
+ {
+ String[] param = StringUtils.split( params[i], "=" );
+ if ( param.length == 1 )
+ {
+ throw new XmlPullParserException( "Missing 'key=value' pair for macro parameter: " + params[i] );
+ }
+
+ String key = unescapeForMacro( param[0] );
+ String value = unescapeForMacro( param[1] );
+ parameters.put( key, value );
+ }
+
+ MacroRequest request = new MacroRequest( sourceContent, new Xhtml5Parser(), parameters, getBasedir() );
+
+ try
+ {
+ executeMacro( macroName, request, sink );
+ }
+ catch ( MacroExecutionException e )
+ {
+ throw new XmlPullParserException( "Unable to execute macro in the document: " + macroName );
+ }
+ catch ( MacroNotFoundException me )
+ {
+ throw new XmlPullParserException( "Macro not found: " + macroName );
+ }
+ }
+
+ /**
+ * escapeForMacro
+ *
+ * @param s String
+ * @return String
+ */
+ private String escapeForMacro( String s )
+ {
+ if ( s == null || s.length() < 1 )
+ {
+ return s;
+ }
+
+ String result = s;
+
+ // use some outrageously out-of-place chars for text
+ // (these are device control one/two in unicode)
+ result = StringUtils.replace( result, "\\=", "\u0011" );
+ result = StringUtils.replace( result, "\\|", "\u0012" );
+
+ return result;
+ }
+
+ /**
+ * unescapeForMacro
+ *
+ * @param s String
+ * @return String
+ */
+ private String unescapeForMacro( String s )
+ {
+ if ( s == null || s.length() < 1 )
+ {
+ return s;
+ }
+
+ String result = s;
+
+ result = StringUtils.replace( result, "\u0011", "=" );
+ result = StringUtils.replace( result, "\u0012", "|" );
+
+ return result;
+ }
+
+ /** {@inheritDoc} */
+ protected void init()
+ {
+ super.init();
+
+ this.boxed = false;
+ this.isEmptyElement = false;
+ }
+
+ /** {@inheritDoc} */
+ public void parse( Reader source, Sink sink )
+ throws ParseException
+ {
+ this.sourceContent = null;
+
+ try
+ {
+ StringWriter contentWriter = new StringWriter();
+ IOUtil.copy( source, contentWriter );
+ sourceContent = contentWriter.toString();
+ }
+ catch ( IOException ex )
+ {
+ throw new ParseException( "Error reading the input source: " + ex.getMessage(), ex );
+ }
+ finally
+ {
+ IOUtil.close( source );
+ }
+
+ try
+ {
+ super.parse( new StringReader( sourceContent ), sink );
+ }
+ finally
+ {
+ this.sourceContent = null;
+ }
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5ParserModule.java b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5ParserModule.java
new file mode 100644
index 0000000..e52cfba
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5ParserModule.java
@@ -0,0 +1,40 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.maven.doxia.parser.module.AbstractParserModule;
+import org.apache.maven.doxia.parser.module.ParserModule;
+import org.codehaus.plexus.component.annotations.Component;
+
+/**
+ * <p>Xhtml5ParserModule class.</p>
+ */
+@Component( role = ParserModule.class, hint = "xhtml5" )
+public class Xhtml5ParserModule
+ extends AbstractParserModule
+{
+ /**
+ * Default constructor.
+ */
+ public Xhtml5ParserModule()
+ {
+ super( "xhtml5" );
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Sink.java b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Sink.java
new file mode 100644
index 0000000..1efe810
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5Sink.java
@@ -0,0 +1,366 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Writer;
+
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.html.HTML.Attribute;
+
+import org.apache.maven.doxia.markup.HtmlMarkup;
+import org.apache.maven.doxia.sink.SinkEventAttributes;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+import org.apache.maven.doxia.sink.impl.SinkUtils;
+import org.apache.maven.doxia.sink.impl.Xhtml5BaseSink;
+import org.apache.maven.doxia.util.HtmlTools;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * <a href="https://www.w3.org/TR/html52/">XHTML 5.2</a> sink implementation.
+ */
+public class Xhtml5Sink
+ extends Xhtml5BaseSink
+ implements Xhtml5Markup
+{
+ // ----------------------------------------------------------------------
+ // Instance fields
+ // ----------------------------------------------------------------------
+
+ private String encoding;
+
+ private String languageId;
+
+ /** An indication on if we're inside a head title. */
+ private boolean headTitleFlag;
+
+ // ----------------------------------------------------------------------
+ // Constructors
+ // ----------------------------------------------------------------------
+
+ /**
+ * Constructor, initialize the Writer.
+ *
+ * @param writer not null writer to write the result.
+ */
+ protected Xhtml5Sink( Writer writer )
+ {
+ super( writer );
+ }
+
+ /**
+ * Constructor, initialize the Writer and tells which encoding is used.
+ *
+ * @param writer not null writer to write the result.
+ * @param encoding the encoding used, that should be written to the generated HTML content
+ * if not <code>null</code>.
+ */
+ protected Xhtml5Sink( Writer writer, String encoding )
+ {
+ super( writer );
+
+ this.encoding = encoding;
+ }
+
+ /**
+ * Constructor, initialize the Writer and tells which encoding and languageId are used.
+ *
+ * @param writer not null writer to write the result.
+ * @param encoding the encoding used, that should be written to the generated HTML content
+ * if not <code>null</code>.
+ * @param languageId language identifier for the root element as defined by
+ * <a href="ftp://ftp.isi.edu/in-notes/bcp/bcp47.txt">IETF BCP 47</a>, Tags for the Identification of Languages;
+ * in addition, the empty string may be specified.
+ */
+ protected Xhtml5Sink( Writer writer, String encoding, String languageId )
+ {
+ this( writer, encoding );
+
+ this.languageId = languageId;
+ }
+
+ /** {@inheritDoc} */
+ public void head()
+ {
+ init();
+
+ setHeadFlag( true );
+
+ write( "<!DOCTYPE html>" );
+
+ MutableAttributeSet atts = new SinkEventAttributeSet();
+ atts.addAttribute( "xmlns", XHTML5_NAMESPACE );
+
+ if ( languageId != null )
+ {
+ atts.addAttribute( Attribute.LANG.toString(), languageId );
+ atts.addAttribute( "xml:lang", languageId );
+ }
+
+ writeStartTag( HTML, atts );
+
+ writeStartTag( HEAD );
+ }
+
+ /** {@inheritDoc} */
+ public void head_()
+ {
+ if ( !isHeadTitleFlag() )
+ {
+ // The content of element type "head" must match
+ // "((script|style|meta|link|object|isindex)*,
+ // ((title,(script|style|meta|link|object|isindex)*,
+ // (base,(script|style|meta|link|object|isindex)*)?)|(base,(script|style|meta|link|object|isindex)*,
+ // (title,(script|style|meta|link|object|isindex)*))))"
+ writeStartTag( TITLE );
+ writeEndTag( TITLE );
+ }
+
+ setHeadFlag( false );
+ setHeadTitleFlag( false );
+
+ if ( encoding != null )
+ {
+ write( "<meta charset=\"" + encoding + "\"/>" );
+ }
+
+ writeEndTag( HEAD );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TITLE
+ */
+ public void title()
+ {
+ setHeadTitleFlag( true );
+
+ writeStartTag( TITLE );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#TITLE
+ */
+ public void title_()
+ {
+ content( getTextBuffer().toString() );
+
+ writeEndTag( TITLE );
+
+ resetTextBuffer();
+
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#META
+ */
+ public void author_()
+ {
+ if ( getTextBuffer().length() > 0 )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttribute( Attribute.NAME, "author" );
+ String text = HtmlTools.escapeHTML( getTextBuffer().toString() );
+ // hack: un-escape numerical entities that have been escaped above
+ // note that numerical entities should really be added as one unicode character in the first place
+ text = StringUtils.replace( text, "&#", "&#" );
+ att.addAttribute( Attribute.CONTENT, text );
+
+ writeSimpleTag( META, att );
+
+ resetTextBuffer();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#META
+ */
+ public void date_()
+ {
+ if ( getTextBuffer().length() > 0 )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttribute( Attribute.NAME, "date" );
+ att.addAttribute( Attribute.CONTENT, getTextBuffer().toString() );
+
+ writeSimpleTag( META, att );
+
+ resetTextBuffer();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BODY
+ */
+ public void body()
+ {
+ writeStartTag( BODY );
+ }
+
+ /**
+ * {@inheritDoc}
+ * @see javax.swing.text.html.HTML.Tag#BODY
+ * @see javax.swing.text.html.HTML.Tag#HTML
+ */
+ public void body_()
+ {
+ writeEndTag( BODY );
+
+ writeEndTag( HTML );
+
+ flush();
+
+ init();
+ }
+
+ /**
+ * Starts a section..
+ *
+ * @param depth The level of the section.
+ * @param attributes some attributes. May be null.
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ protected void onSection( int depth, SinkEventAttributes attributes )
+ {
+ if ( depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_5 )
+ {
+ MutableAttributeSet att = new SinkEventAttributeSet();
+ att.addAttributes( SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_BASE_ATTRIBUTES ) );
+
+ writeStartTag( HtmlMarkup.SECTION, att );
+ }
+ }
+
+ /**
+ * Ends a section.
+ *
+ * @param depth The level of the section.
+ * @see javax.swing.text.html.HTML.Tag#DIV
+ */
+ protected void onSection_( int depth )
+ {
+ if ( depth >= SECTION_LEVEL_1 && depth <= SECTION_LEVEL_5 )
+ {
+ writeEndTag( HtmlMarkup.SECTION );
+ }
+ }
+
+ /**
+ * Starts a section title.
+ *
+ * @param depth The level of the section title.
+ * @param attributes some attributes. May be null.
+ * @see javax.swing.text.html.HTML.Tag#H2
+ * @see javax.swing.text.html.HTML.Tag#H3
+ * @see javax.swing.text.html.HTML.Tag#H4
+ * @see javax.swing.text.html.HTML.Tag#H5
+ * @see javax.swing.text.html.HTML.Tag#H6
+ */
+ protected void onSectionTitle( int depth, SinkEventAttributes attributes )
+ {
+ MutableAttributeSet atts = SinkUtils.filterAttributes(
+ attributes, SinkUtils.SINK_SECTION_ATTRIBUTES );
+
+ if ( depth == SECTION_LEVEL_1 )
+ {
+ writeStartTag( HtmlMarkup.H2, atts );
+ }
+ else if ( depth == SECTION_LEVEL_2 )
+ {
+ writeStartTag( HtmlMarkup.H3, atts );
+ }
+ else if ( depth == SECTION_LEVEL_3 )
+ {
+ writeStartTag( HtmlMarkup.H4, atts );
+ }
+ else if ( depth == SECTION_LEVEL_4 )
+ {
+ writeStartTag( HtmlMarkup.H5, atts );
+ }
+ else if ( depth == SECTION_LEVEL_5 )
+ {
+ writeStartTag( HtmlMarkup.H6, atts );
+ }
+ }
+
+ /**
+ * Ends a section title.
+ *
+ * @param depth The level of the section title.
+ * @see javax.swing.text.html.HTML.Tag#H2
+ * @see javax.swing.text.html.HTML.Tag#H3
+ * @see javax.swing.text.html.HTML.Tag#H4
+ * @see javax.swing.text.html.HTML.Tag#H5
+ * @see javax.swing.text.html.HTML.Tag#H6
+ */
+ protected void onSectionTitle_( int depth )
+ {
+ if ( depth == SECTION_LEVEL_1 )
+ {
+ writeEndTag( HtmlMarkup.H2 );
+ }
+ else if ( depth == SECTION_LEVEL_2 )
+ {
+ writeEndTag( HtmlMarkup.H3 );
+ }
+ else if ( depth == SECTION_LEVEL_3 )
+ {
+ writeEndTag( HtmlMarkup.H4 );
+ }
+ else if ( depth == SECTION_LEVEL_4 )
+ {
+ writeEndTag( HtmlMarkup.H5 );
+ }
+ else if ( depth == SECTION_LEVEL_5 )
+ {
+ writeEndTag( HtmlMarkup.H6 );
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Public protected methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * <p>Setter for the field <code>headTitleFlag</code>.</p>
+ *
+ * @param headTitleFlag an header title flag.
+ * @since 1.1
+ */
+ protected void setHeadTitleFlag( boolean headTitleFlag )
+ {
+ this.headTitleFlag = headTitleFlag;
+ }
+
+ /**
+ * <p>isHeadTitleFlag.</p>
+ *
+ * @return the current headTitleFlag.
+ * @since 1.1
+ */
+ protected boolean isHeadTitleFlag()
+ {
+ return this.headTitleFlag ;
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkFactory.java b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkFactory.java
new file mode 100644
index 0000000..7421c9a
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/main/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkFactory.java
@@ -0,0 +1,47 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Writer;
+
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.SinkFactory;
+import org.apache.maven.doxia.sink.impl.AbstractXmlSinkFactory;
+import org.codehaus.plexus.component.annotations.Component;
+
+/**
+ * Xhtml implementation of the Sink factory.
+ */
+@Component( role = SinkFactory.class, hint = "xhtml5" )
+public class Xhtml5SinkFactory
+ extends AbstractXmlSinkFactory
+{
+ /** {@inheritDoc} */
+ protected Sink createSink( Writer writer, String encoding )
+ {
+ return new Xhtml5Sink( writer, encoding );
+ }
+
+ /** {@inheritDoc} */
+ protected Sink createSink( Writer writer, String encoding, String languageId )
+ {
+ return new Xhtml5Sink( writer, encoding, languageId );
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/site/site.xml b/doxia-modules/doxia-module-xhtml5/src/site/site.xml
new file mode 100644
index 0000000..33c2393
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/site/site.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+ -->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd"
+ name="Xhtml">
+
+ <body>
+
+ <menu ref="parent"/>
+
+ <menu name="Overview">
+ <item name="Introduction" href="index.html"/>
+ <item name="JavaDocs" href="apidocs/index.html"/>
+ <item name="Source Xref" href="xref/index.html"/>
+ <!--item name="FAQ" href="faq.html"/-->
+ </menu>
+
+ <menu ref="reports"/>
+
+ </body>
+
+</project>
\ No newline at end of file
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5IdentityTest.java b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5IdentityTest.java
new file mode 100644
index 0000000..0cf827e
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5IdentityTest.java
@@ -0,0 +1,87 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Writer;
+
+import org.apache.maven.doxia.module.AbstractIdentityTest;
+import org.apache.maven.doxia.module.xhtml5.Xhtml5Parser;
+import org.apache.maven.doxia.module.xhtml5.Xhtml5Sink;
+import org.apache.maven.doxia.parser.Parser;
+import org.apache.maven.doxia.sink.Sink;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Check that piping a full model through an Xhtml5Parser and an Xhtml5Sink
+ * leaves the model unchanged.
+ */
+public class Xhtml5IdentityTest
+ extends AbstractIdentityTest
+{
+ /** {@inheritDoc} */
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+ assertIdentity( true );
+ }
+
+ /** {@inheritDoc} */
+ protected Sink createSink( Writer writer )
+ {
+ Xhtml5Sink sink = new Xhtml5Sink( writer );
+ sink.setInsertNewline( false );
+ return sink;
+ }
+
+ /** {@inheritDoc} */
+ protected Parser createParser()
+ {
+ return new Xhtml5Parser();
+ }
+
+ /** {@inheritDoc} */
+ protected String getExpected()
+ {
+ // DOXIA-177
+ String expected = super.getExpected();
+
+ String startCaption = "begin:tableCaption";
+ String endCaption = "end:tableCaption";
+
+ int iStartCaption = expected.indexOf( startCaption );
+ int iEndCaption = expected.indexOf( endCaption ) + endCaption.length();
+
+ String captionTag = expected.substring( iStartCaption, iEndCaption ) + EOL + EOL + EOL;
+ expected = StringUtils.replace( expected, captionTag, "" );
+
+ int iStartTableRows =
+ expected.substring( 0, iStartCaption ).lastIndexOf( "begin:tableRows" ) + "begin:tableRows".length();
+
+ StringBuilder text = new StringBuilder();
+ text.append( expected.substring( 0, iStartTableRows ) );
+ text.append( EOL + EOL + EOL );
+ text.append( captionTag.subSequence( 0, captionTag.indexOf( "end:tableCaption" )
+ + "end:tableCaption".length() ) );
+ text.append( expected.substring( iStartTableRows ) );
+
+ return text.toString();
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5ParserTest.java b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5ParserTest.java
new file mode 100644
index 0000000..fa4c836
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5ParserTest.java
@@ -0,0 +1,196 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+
+import org.apache.maven.doxia.module.xhtml5.Xhtml5Parser;
+import org.apache.maven.doxia.parser.AbstractParserTest;
+import org.apache.maven.doxia.parser.Parser;
+import org.apache.maven.doxia.sink.impl.SinkEventElement;
+import org.apache.maven.doxia.sink.impl.SinkEventTestingSink;
+
+public class Xhtml5ParserTest
+ extends AbstractParserTest
+{
+ private Xhtml5Parser parser;
+
+ /** {@inheritDoc} */
+ protected void setUp()
+ throws Exception
+ {
+ super.setUp();
+
+ parser = (Xhtml5Parser) lookup( Parser.ROLE, Xhtml5Parser.ROLE_HINT );
+
+ // AbstractXmlParser.CachedFileEntityResolver downloads DTD/XSD files in ${java.io.tmpdir}
+ // Be sure to delete them
+ String tmpDir = System.getProperty( "java.io.tmpdir" );
+
+ // Using FileFilter, because is it is much faster then FileUtils.listFiles
+ File[] tmpFiles = new File( tmpDir ).listFiles( new FileFilter()
+ {
+ Pattern xsdPatterns = Pattern.compile( "(xhtml-lat1.ent|xhtml1-transitional.dtd|xhtml-special.ent|xhtml-symbol.ent)" );
+
+ @Override
+ public boolean accept( File pathname )
+ {
+ return xsdPatterns.matcher( pathname.getName() ).matches();
+ }
+ } );
+
+ for ( File tmpFile : tmpFiles )
+ {
+ tmpFile.delete();
+ }
+
+ }
+
+ /** {@inheritDoc} */
+ protected Parser createParser()
+ {
+ return parser;
+ }
+
+ /** {@inheritDoc} */
+ protected String outputExtension()
+ {
+ return "xhtml";
+ }
+
+ /** @throws Exception */
+ public void testDocumentBodyEventsList()
+ throws Exception
+ {
+ String text = "<html><body></body></html>";
+
+ SinkEventTestingSink sink = new SinkEventTestingSink();
+
+ ( (Xhtml5Parser) createParser() ).parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "body", it.next().getName() );
+ assertEquals( "body_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testHeadEventsList()
+ throws Exception
+ {
+ String text = "<head><title>Title</title><meta name=\"author\" content=\"Author\" />"
+ + "<meta name=\"date\" content=\"Date\" /><meta name=\"security\" content=\"low\"/></head>";
+
+ SinkEventTestingSink sink = new SinkEventTestingSink();
+
+ ( (Xhtml5Parser) createParser() ).parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "head", it.next().getName() );
+ assertEquals( "title", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "title_", it.next().getName() );
+ assertEquals( "author", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "author_", it.next().getName() );
+ assertEquals( "date", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "date_", it.next().getName() );
+ assertEquals( "unknown", it.next().getName() );
+ assertEquals( "head_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testPreEventsList()
+ throws Exception
+ {
+ String text = "<pre></pre>";
+
+ SinkEventTestingSink sink = new SinkEventTestingSink();
+
+ ( (Xhtml5Parser) createParser() ).parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "verbatim", it.next().getName() );
+ assertEquals( "verbatim_", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /**
+ * Test unknown tags.
+ *
+ * @throws java.lang.Exception if any.
+ */
+ public void testUnknown()
+ throws Exception
+ {
+ String text = "<applet><param name=\"name\" value=\"value\"/><unknown/></applet>";
+
+ SinkEventTestingSink sink = new SinkEventTestingSink();
+
+ ( (Xhtml5Parser) createParser() ).parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+ assertEquals( "unknown", it.next().getName() );
+ assertEquals( "unknown", it.next().getName() );
+ assertEquals( "unknown", it.next().getName() );
+ assertEquals( "unknown", it.next().getName() );
+ assertFalse( it.hasNext() );
+ }
+
+ /** @throws Exception */
+ public void testTocMacro()
+ throws Exception
+ {
+ String text = "<html><body>" +
+ "<!-- MACRO{toc|fromDepth=1|toDepth=2} -->" +
+ "<h1>heading 1</h1><h2>heading 2</h2><h3>heading 3</h3>" +
+ "</body></html>";
+
+ SinkEventTestingSink sink = new SinkEventTestingSink();
+
+ ( (Xhtml5Parser) createParser() ).parse( text, sink );
+
+ Iterator<SinkEventElement> it = sink.getEventList().iterator();
+
+ assertEquals( "body", it.next().getName() );
+ assertEquals( "list", it.next().getName() );
+ assertEquals( "listItem", it.next().getName() );
+ assertEquals( "link", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "link_", it.next().getName() );
+ assertEquals( "list", it.next().getName() );
+ assertEquals( "listItem", it.next().getName() );
+ assertEquals( "link", it.next().getName() );
+ assertEquals( "text", it.next().getName() );
+ assertEquals( "link_", it.next().getName() );
+ assertEquals( "listItem_", it.next().getName() );
+ assertEquals( "list_", it.next().getName() );
+ assertEquals( "listItem_", it.next().getName() );
+ assertEquals( "list_", it.next().getName() );
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java
new file mode 100644
index 0000000..133d7aa
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkTest.java
@@ -0,0 +1,449 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.StringWriter;
+import java.io.Writer;
+
+import org.apache.maven.doxia.markup.HtmlMarkup;
+import org.apache.maven.doxia.module.xhtml5.Xhtml5Sink;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.impl.AbstractSinkTest;
+import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
+
+public class Xhtml5SinkTest
+ extends AbstractSinkTest
+{
+ /** {@inheritDoc} */
+ protected String outputExtension()
+ {
+ return "html";
+ }
+
+ /** {@inheritDoc} */
+ protected Sink createSink( Writer writer )
+ {
+ return new Xhtml5Sink( writer, "UTF-8" );
+ }
+
+ /** {@inheritDoc} */
+ protected boolean isXmlSink()
+ {
+ return true;
+ }
+
+ /**
+ * Test link generation.
+ *
+ * @throws java.lang.Exception if any.
+ */
+ public void testLinks()
+ throws Exception
+ {
+ Xhtml5Sink sink = null;
+ Writer writer = new StringWriter();
+ try
+ {
+ sink = (Xhtml5Sink) createSink( writer );
+ sink.link( "http:/www.xdoc.com" );
+ sink.link_();
+ sink.link( "./index.html#anchor" );
+ sink.link_();
+ sink.link( "../index.html#anchor" );
+ sink.link_();
+ sink.link( "index.html" );
+ sink.link_();
+ }
+ finally
+ {
+ if ( sink != null )
+ {
+ sink.close();
+ }
+ }
+
+ String actual = writer.toString();
+ assertTrue( actual.indexOf( "<a class=\"externalLink\" href=\"http:/www.xdoc.com\"></a>" ) != -1 );
+ assertTrue( actual.indexOf( "<a href=\"./index.html#anchor\"></a>" ) != -1 );
+ assertTrue( actual.indexOf( "<a href=\"../index.html#anchor\"></a>" ) != -1 );
+ assertTrue( actual.indexOf( "<a href=\"index.html\"></a>" ) != -1 );
+ }
+
+ /** {@inheritDoc} */
+ protected String getTitleBlock( String title )
+ {
+ return "<title>" + title + "</title>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getAuthorBlock( String author )
+ {
+ return author;
+ }
+
+ /** {@inheritDoc} */
+ protected String getDateBlock( String date )
+ {
+ return date;
+ }
+
+ /** {@inheritDoc} */
+ protected String getHeadBlock()
+ {
+ return "<!DOCTYPE html\">" +
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title></title>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBodyBlock()
+ {
+ return "<body></body></html>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getArticleBlock()
+ {
+ return "<article></article>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNavigationBlock()
+ {
+ return "<nav></nav>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSidebarBlock()
+ {
+ return "<aside></aside>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSectionTitleBlock( String title )
+ {
+ return title;
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection1Block( String title )
+ {
+ return "<section><header>\n<h2>" + title + "</h2></header></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection2Block( String title )
+ {
+ return "<section><header>\n<h3>" + title + "</h3></header></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection3Block( String title )
+ {
+ return "<section><header>\n<h4>" + title + "</h4></header></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection4Block( String title )
+ {
+ return "<section><header>\n<h5>" + title + "</h5></header></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection5Block( String title )
+ {
+ return "<section><header>\n<h6>" + title + "</h6></header></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getHeaderBlock()
+ {
+ return "<header></header>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getContentBlock()
+ {
+ return "<main>" + EOL + "<div class=\"content\"></div></main>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFooterBlock()
+ {
+ return "<footer></footer>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getListBlock( String item )
+ {
+ return "<ul>\n<li>" + item + "</li></ul>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNumberedListBlock( String item )
+ {
+ return "<ol style=\"list-style-type: lower-roman\">\n<li>" + item + "</li></ol>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDefinitionListBlock( String definum, String definition )
+ {
+ return "<dl>\n<dt>" + definum + "</dt>\n<dd>" + definition + "</dd></dl>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFigureBlock( String source, String caption )
+ {
+ String figureBlock = "<figure><img src=\"" + source + "\" alt=\"\" />";
+ if( caption != null )
+ {
+ figureBlock += "<figcaption>" + caption + "</figcaption>";
+ }
+ figureBlock += "</figure>";
+ return figureBlock;
+ }
+
+ /** {@inheritDoc} */
+ protected String getTableBlock( String cell, String caption )
+ {
+ return "<table border=\"0\" class=\"bodyTable\">"
+ + "<caption>Table caption</caption><tr class=\"a\">\n<td>cell</td></tr>"
+ + "</table>";
+ }
+
+ // Disable testTable until the order of attributes issue is clarified
+ // TODO: remove
+ /** {@inheritDoc} */
+ public void testTable()
+ {
+ assertEquals( "Dummy!", "", "" );
+ }
+
+ /** {@inheritDoc} */
+ protected String getParagraphBlock( String text )
+ {
+ return "<p>" + text + "</p>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDataBlock( String value, String text )
+ {
+ return "<data value=\"" + value + "\">" + text + "</data>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getTimeBlock( String datetime, String text )
+ {
+ return "<time datetime=\"" + datetime + "\">" + text + "</time>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getAddressBlock( String text )
+ {
+ return "<address>" + text + "</address>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBlockquoteBlock( String text )
+ {
+ return "<blockquote>" + text + "</blockquote>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDivisionBlock( String text )
+ {
+ return "<div>" + text + "</div>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getVerbatimBlock( String text )
+ {
+ return "<div class=\"source\">\n<pre>" + text + "</pre></div>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getHorizontalRuleBlock()
+ {
+ return "<hr />";
+ }
+
+ /** {@inheritDoc} */
+ protected String getPageBreakBlock()
+ {
+ return "<!-- PB -->";
+ }
+
+ /** {@inheritDoc} */
+ protected String getAnchorBlock( String anchor )
+ {
+ return "<a name=\"" + anchor + "\">" + anchor + "</a>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getLinkBlock( String link, String text )
+ {
+ return "<a href=\"" + link + "\">" + text + "</a>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBlock( String text )
+ {
+ return text;
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineItalicBlock( String text )
+ {
+ return "<i>" + text + "</i>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineBoldBlock( String text )
+ {
+ return "<b>" + text + "</b>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getInlineCodeBlock( String text )
+ {
+ return "<code>" + text + "</code>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getItalicBlock( String text )
+ {
+ return "<i>" + text + "</i>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBoldBlock( String text )
+ {
+ return "<b>" + text + "</b>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getMonospacedBlock( String text )
+ {
+ return "<code>" + text + "</code>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getLineBreakBlock()
+ {
+ return "<br />";
+ }
+
+ /** {@inheritDoc} */
+ protected String getLineBreakOpportunityBlock()
+ {
+ return "<wbr />";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNonBreakingSpaceBlock()
+ {
+ return " ";
+ }
+
+ /** {@inheritDoc} */
+ protected String getTextBlock( String text )
+ {
+ // TODO: need to be able to retreive those from outside the sink
+ return "~,_=,_-,_+,_*,_[,_],_<,_>,_{,_},_\\";
+ }
+
+ /** {@inheritDoc} */
+ protected String getRawTextBlock( String text )
+ {
+ return text;
+ }
+
+ /**
+ * Test entities is section titles and paragraphs.
+ */
+ public void testEntities()
+ {
+ Xhtml5Sink sink = null;
+ Writer writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5Sink( writer );
+ sink.section( Sink.SECTION_LEVEL_1, null );
+ sink.header();
+ sink.sectionTitle( Sink.SECTION_LEVEL_1, null );
+ sink.text( "&", null );
+ sink.sectionTitle_( Sink.SECTION_LEVEL_1 );
+ sink.header_();
+ sink.paragraph( null );
+ sink.text( "&", null );
+ sink.paragraph_();
+ sink.section_( Sink.SECTION_LEVEL_1 );
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ assertEquals( "<section><header>\n<h2>&</h2></header>\n<p>&</p></section>", writer.toString() );
+ }
+
+ /**
+ * Test head events.
+ */
+ public void testHead()
+ {
+ Xhtml5Sink sink = null;
+ Writer writer = new StringWriter();
+
+ try
+ {
+ sink = new Xhtml5Sink( writer );
+ sink.head();
+ sink.title();
+ sink.text( "Title" );
+ sink.title_();
+ sink.comment( "A comment" );
+ sink.author();
+ // note: this is really illegal, there should be no un-resolved entities emitted into text()
+ sink.text( "ģ&" );
+ sink.author_();
+ SinkEventAttributeSet atts = new SinkEventAttributeSet( 1 );
+ atts.addAttribute( "href", "http://maven.apache.org/" );
+ sink.unknown( "base", new Object[] {new Integer( HtmlMarkup.TAG_TYPE_SIMPLE )}, atts );
+ sink.head_();
+ }
+ finally
+ {
+ sink.close();
+ }
+
+ String expected =
+ "<head>\n<title>Title</title><!--A comment--><meta name=\"author\" content=\"ģ&\" />"
+ + "<base href=\"http://maven.apache.org/\" /></head>";
+ String actual = writer.toString();
+ assertTrue( actual, actual.indexOf( expected ) != -1 );
+ }
+
+ /** {@inheritDoc} */
+ protected String getCommentBlock( String text )
+ {
+ return "<!--" + toXmlComment( text ) + "-->";
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkWithLanguageIdTest.java b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkWithLanguageIdTest.java
new file mode 100644
index 0000000..3a9945e
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/java/org/apache/maven/doxia/module/xhtml5/Xhtml5SinkWithLanguageIdTest.java
@@ -0,0 +1,45 @@
+package org.apache.maven.doxia.module.xhtml5;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.Writer;
+import java.util.Locale;
+
+import org.apache.maven.doxia.module.xhtml5.Xhtml5Sink;
+import org.apache.maven.doxia.sink.Sink;
+
+public class Xhtml5SinkWithLanguageIdTest
+ extends Xhtml5SinkTest
+{
+ /** {@inheritDoc} */
+ protected Sink createSink( Writer writer )
+ {
+ return new Xhtml5Sink( writer, "UTF-8", Locale.US.getLanguage() );
+ }
+
+ /** {@inheritDoc} */
+ protected String getHeadBlock()
+ {
+ return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
+ + "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">"
+ + "<head><title></title>"
+ + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/></head>";
+ }
+}
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/resources/download.apt.vm b/doxia-modules/doxia-module-xhtml5/src/test/resources/download.apt.vm
new file mode 100644
index 0000000..6e09992
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/resources/download.apt.vm
@@ -0,0 +1,79 @@
+ ------
+Download Maven ${currentVersion}
+ ------
+Brett Porter
+Jason van Zyl
+ ------
+4 October 2005
+ ------
+
+Download Maven ${currentVersion}
+
+ Maven is distributed in several formats for your convenience.
+
+ You will be prompted for a mirror - if the file is not found on yours, please be patient, as it may take 24
+ hours to reach all mirrors.
+
+ Maven ${currentVersion} is distributed under the {{{http://maven.apache.org/license.html} Apache License, version 2.0}}.
+
+ We <<strongly>> encourage our users to configure a Maven repository mirror closer to their location, please read {{{guides/mini/guide-mirror-settings.html} How to Use Mirrors for Repositories}}.
+
+*-------------------------+---------+----------+-----------+
+| | Mirrors | Checksum | Signature |
+*-------------------------+---------+----------+-----------+
+| Maven ${currentVersion} (tar.bz2) | {{{http://www.apache.org/dyn/closer.cgi/maven/binaries/maven-${currentVersion}-bin.tar.bz2} maven-${currentVersion}-bin.tar.bz2}} | {{{http://www.apache.org/dist/maven/binaries/maven-${currentVersion}-bin.tar.bz2.md5} maven-${currentVersion}-bin.tar.bz2.md5}} | {{{http://www.apache.org/dist/maven/binaries/maven-${currentVersion}-bin.tar.bz2.asc} maven-${currentVersion}-bin.tar.bz2.asc}} |
+*-------------------------+---------+----------+-----------+
+| Maven ${currentVersion} (tar.gz) | {{{http://www.apache.org/dyn/closer.cgi/maven/binaries/maven-${currentVersion}-bin.tar.gz} maven-${currentVersion}-bin.tar.gz}} | {{{http://www.apache.org/dist/maven/binaries/maven-${currentVersion}-bin.tar.gz.md5} maven-${currentVersion}-bin.tar.gz.md5}} | {{{http://www.apache.org/dist/maven/binaries/maven-${currentVersion}-bin.tar.gz.asc} maven-${currentVersion}-bin.tar.gz.asc}} |
+*-------------------------+---------+----------+-----------+
+| Maven ${currentVersion} (zip) | {{{http://www.apache.org/dyn/closer.cgi/maven/binaries/maven-${currentVersion}-bin.zip} maven-${currentVersion}-bin.zip}} | {{{http://www.apache.org/dist/maven/binaries/maven-${currentVersion}-bin.zip.md5} maven-${currentVersion}-bin.zip.md5}} | {{{http://www.apache.org/dist/maven/binaries/maven-${currentVersion}-bin.zip.asc} maven-${currentVersion}-bin.zip.asc}} |
+*-------------------------+---------+----------+-----------+
+| Maven Ant Tasks 2.0.7 | {{{http://www.apache.org/dyn/closer.cgi/maven/binaries/maven-ant-tasks-2.0.7.jar} maven-ant-tasks-2.0.7.jar}} | {{{http://www.apache.org/dist/maven/binaries/maven-ant-tasks-2.0.7.jar.md5} maven-ant-tasks-2.0.7.jar.md5}} | {{{http://www.apache.org/dist/maven/binaries/maven-ant-tasks-2.0.7.jar.asc} maven-ant-tasks-2.0.7.jar.asc}} |
+*-------------------------+---------+----------+-----------+
+
+* Previous Releases
+
+ All previous releases of Maven can be found in the {{{http://archive.apache.org/dist/maven/binaries/}archives}}.
+
+* System {Requirements}
+
+*----------------------+---------------------------------------------------------------------------------------------+
+| <<JDK>> | 1.4 or above (this is to execute Maven - it still allows you to build against 1.3 and prior JDK's)
+*----------------------+---------------------------------------------------------------------------------------------+
+| <<Memory>> | No minimum requirement
+*----------------------+---------------------------------------------------------------------------------------------+
+| <<Disk>> | No minimum requirement. Approximately 100MB will be used for your local repository, however this will vary depending on usage and can be removed and redownloaded at any time.
+*----------------------+---------------------------------------------------------------------------------------------+
+| <<Operating System>> | No minimum requirement. On Windows, Windows NT and above or Cygwin is required for the startup scripts. Tested on Windows XP, Fedora Core and Mac OS X.
+*----------------------+---------------------------------------------------------------------------------------------+
+
+* {Installation} Instructions
+
+** Windows 2000/XP
+
+ [[1]] Unzip <<<maven-${currentVersion}-bin.zip>>> to the directory you wish to install Maven ${currentVersion}. These instructions
+ assume you chose <<<C:\Program Files\Apache Software Foundation\maven-${currentVersion}>>>
+
+ [[2]] Add the <<<bin>>> directory to your path, by opening up the system properties (WinKey + Pause),
+ selecting the "Advanced" tab, and the "Environment Variables" button, then editing the <<<PATH>>>
+ variable in the user variables. eg.
+ <<<"C:\Program Files\Apache Software Foundation\maven-${currentVersion}\bin";%PATH%>>>
+
+ [[3]] In the same dialog, make sure that <<<JAVA_HOME>>> is set to the location of your JDK,
+ eg. <<<C:\Program Files\Java\jdk1.5.0_02>>>
+
+ [[4]] Run <<<mvn --version>>> to verify that it is correctly installed.
+
+** Unix-based Operating Systems (Linux, Solaris and Mac OS X)
+
+ [[1]] Extract the distribution archive to the directory you wish to install Maven ${currentVersion}. These instructions
+ assume you chose <<</usr/local/maven-${currentVersion}>>>. The directory <<<maven-${currentVersion}>>> will be created from
+ the archive.
+
+ [[2]] Add the <<<bin>>> directory to your path, eg. <<<export
+PATH=/usr/local/maven-${currentVersion}/bin:$PATH>>>
+
+ [[3]] Make sure that <<<JAVA_HOME>>> is set to the location of your JDK, eg.
+ <<<export JAVA_HOME=/usr/java/jdk1.5.0_02>>>
+
+ [[4]] Run <<<mvn --version>>> to verify that it is correctly installed.
+
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/resources/file.with.dot.in.name.xml b/doxia-modules/doxia-module-xhtml5/src/test/resources/file.with.dot.in.name.xml
new file mode 100644
index 0000000..8a0bb34
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/resources/file.with.dot.in.name.xml
@@ -0,0 +1,20 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<nothing/>
\ No newline at end of file
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/resources/fun.html b/doxia-modules/doxia-module-xhtml5/src/test/resources/fun.html
new file mode 100644
index 0000000..059aca5
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/resources/fun.html
@@ -0,0 +1,66 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html>
+ <head>
+ <title>This is fun!</title>
+ </head>
+ <body>
+ <h1>This is the first first-level section</h1>
+ <p>
+ This paragraph belongs to section one.
+ </p>
+ <h2>This is the first second-level section</h2>
+ <p>
+ <a name="para1" />This paragraph belongs to subsection one.
+ </p>
+ <h2>This is the second second-level section</h2>
+ <p>
+ This paragraph belongs to subsection two.
+ </p>
+ <h4>This is the first third-level section</h4>
+ <p>
+ To make the <em>task</em> <i>even</i> harder,
+ the <tt>h3</tt>-heading was dropped, but we
+ expect the parser to recognize this section
+ as level 3, not level 4.
+ </p>
+ <h2>This is the third second-level section</h2>
+ <p>
+ This paragraph belongs to subsection three.
+ </p>
+ <h1>This is the second first-level section</h1>
+ <p>
+ This paragraph belongs to section two.
+ </p>
+ <pre>
+ //what is source code?
+ </pre>
+ <p>
+ This is <em>also</em> a <strong>paragraph</strong>. Take a look
+ at the <a href="#para1">other paragraph</a>.
+ </p>
+ <p>
+ Just introduce some <img src="http://maven.apache.org/images/logos/maven-feather.png"/>
+ images. <img src="http://maven.apache.org/images/logos/maven-feather.png" alt="maven feather"/>
+ <img src="http://maven.apache.org/images/logos/maven-feather.png" alt="maven feather"
+ title="built by: maven"/>
+ </p>
+ </body>
+</html>
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/resources/index.xml.vm b/doxia-modules/doxia-module-xhtml5/src/test/resources/index.xml.vm
new file mode 100644
index 0000000..0050c11
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/resources/index.xml.vm
@@ -0,0 +1,231 @@
+<?xml version="1.0"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<document>
+ <properties>
+ <title>Welcome to Maven</title>
+ <author email="brett@apache.org">Brett Porter</author>
+ <author email="jason@sonatype.com">Jason van Zyl</author>
+ </properties>
+ <body>
+
+ <!-- TODO: news? -->
+ <div id="downloadbox">
+ <h5>Search Maven Sites</h5>
+<!-- Google CSE Search Box Begins -->
+<form action="http://www.google.com/cse" id="searchbox_006660305041243700248:hyqtfwsewpm">
+ <input type="hidden" name="cx" value="006660305041243700248:hyqtfwsewpm" />
+ <input type="text" name="q" size="25" />
+ <input type="submit" name="sa" value="Search" />
+</form>
+<script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_006660305041243700248%3Ahyqtfwsewpm"></script>
+<!-- Google CSE Search Box Ends -->
+
+ <h5>Get Maven ${currentVersion}</h5>
+ <span style="display: block; text-align: right; font-size: smaller">Released: 20 June 2007</span>
+ <p>
+ <a href="download.html">
+ <img src="images/folder-open.gif" border="0" alt="" title="Download Maven ${currentVersion}"/>
+ Maven ${currentVersion}
+ </a>
+ <small>(1.3Mb)</small>
+ <span style="font-size: smaller">
+ <br/>
+ <a href="download.html#Requirements">System Requirements</a>,
+ <a href="download.html#Installation">Installation Instructions</a>,
+ <a href="release-notes.html">Release Notes</a>
+ </span>
+ </p>
+ <p>
+ <a href="download.html">
+ <img src="images/folder-open.gif" border="0" alt="" title="Download Maven Tasks for Ant 2.0.7"/>
+ Maven Tasks for Ant 2.0.7
+ </a>
+ <small>(938k)</small>
+ <span style="font-size: smaller">
+ <br/>
+ <a href="ant-tasks.html">Documentation</a>,
+ <a href="ant-tasks-release-notes.html">Release Notes</a>
+ </span>
+ </p>
+ <!-- TODO: what about downloads for Continuum, etc.? Would be good to have one big download page -->
+
+ <h5>Other Maven Projects</h5>
+ <p>
+ <a href="/continuum/">
+ <img src="images/continuum.png" border="0" width="76" height="32" style="float: left; margin-right: 1em;" alt="" title="Continuum" />
+ Continuum
+ </a>
+ continuous integration server
+ </p>
+ <!--
+
+ You can't be promoting Archiva when it's never been released, it's completely alpha and this is misleading.
+ When it's released I think it can rightfully be put here.
+
+ <p>
+ <a href="archiva">
+ <img src="images/archiva.png" border="0" width="76" height="32" style="float: left; margin-right: 1em;" alt="" title="Archiva" />
+ Archiva
+ </a>
+ repository and artifact management server
+ </p>
+ -->
+ <p>
+ <a href="/maven-1.x/">
+ <img src="images/maven-1.x.png" border="0" width="76" height="32" style="float: left; margin-right: 1em;" alt="" title="Maven 1.x" />
+ Maven 1.x
+ </a>
+ All stories start at the beginning...
+ </p>
+
+ <!-- TODO: we should use the SSI instead, but two things prevent it: a) the SSI's aren't working on apache.org yet so I can't test it; b) SSI's get eliminated from xdoc. For some reason even inside CDATA they are escaped. -->
+ <iframe src="http://www.apache.org/ads/bannerbar.html"
+style="margin-left: -10px; padding: 0;" frameborder="0" scrolling="no"
+width="244" height="68"></iframe>
+ <div>
+ <a href="http://www.ossummit.com"><img src="http://www.ossummit.com/ads/ossummit_button_2.jpg" alt="OS Summit Asia" border="0" width="234" height="60" /></a>
+ </div>
+ </div>
+ <section name="Welcome to Maven">
+
+ <!-- TODO: I reckon it's time for a new description -->
+ <p>
+ Maven is a software project management and comprehension tool. Based on the concept of a project object model
+ (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
+ </p>
+ <p>
+ If you think that Maven could help your project, you can find out more information about in the "About Maven"
+ section of the navigation. This includes an in-depth description of <a href="what-is-maven.html">what Maven is</a>,
+ a <a href="maven-features.html">list of some of its main features</a>, and a set of <a href="general.html">frequently
+ asked questions about what Maven is</a>.
+ </p>
+ <h3>Learning about Maven</h3>
+ <p>
+ <!-- TODO: this could be the big button type thing instead of a list of links -->
+ This site is separated into the following sections, depending on how you'd like to use Maven:
+ </p>
+ <!-- TODO: use CSS -->
+ <ul>
+ <li>
+ <span style="white-space:nowrap; font-weight: bold; font-size: 1.25em">
+ <a href="run-maven/index.html">Run Maven</a>
+ </span>
+ <span style="display: block; margin-bottom: 0.5em">
+ Information for those needing to build a project that uses Maven
+ </span>
+ </li>
+ <li>
+ <span style="white-space:nowrap; font-weight: bold; font-size: 1.25em">
+ <a href="users/index.html">Use Maven</a>
+ </span>
+ <span style="display: block; margin-bottom: 0.5em">
+ Information for those wanting to use Maven to build their project, including a "10 minute test" that gives a
+ practical overview of Maven's main features in just 10 minutes
+ </span>
+ </li>
+ <li>
+ <span style="white-space:nowrap; font-weight: bold; font-size: 1.25em">
+ <a href="plugin-developers/index.html">Write Maven Plugins</a>
+ </span>
+ <span style="display: block; margin-bottom: 0.5em">
+ Information for those who may or may not be using Maven, but want to provide a plugin for shared
+ functionality or to accompany their own product or toolset
+ </span>
+ </li>
+ <li>
+ <span style="white-space:nowrap; font-weight: bold; font-size: 1.25em">
+ <a href="repository/index.html">Improve the Maven Repository</a>
+ </span>
+ <span style="display: block; margin-bottom: 0.5em">
+ Information for those who may or may not use, but are interested in getting project metadata into the
+ repository
+ </span>
+ </li>
+ <li>
+ <span style="white-space:nowrap; font-weight: bold; font-size: 1.25em">
+ <a href="developers/index.html">Develop Maven</a>
+ </span>
+ <span style="display: block; margin-bottom: 0.5em">
+ Information for those who are currently developers, or interested in becoming developers of the Maven
+ project itself
+ </span>
+ </li>
+ </ul>
+ <p>
+ Each guide is divided into a number of trails to get you started on a particular topic, and includes a
+ reference area and a "cookbook" of common examples.
+ </p>
+ <p>
+ You can access the guides at any time from the left navigation.
+ </p>
+ <h3>Documentation Index</h3>
+ <p>
+ If you are looking for a quick reference, you can use the <a href="guides/index.html">documentation index.</a>
+<!-- TODO
+ If you are looking for a quick reference, you can use the documentation index. It is available in both
+ <a href="todo.html">alphabetical</a> and <a href="todo.html">categorical</a> listing formats.
+-->
+ </p>
+ <h3>Plugins</h3>
+<!-- TODO
+ <p>
+ Maven functionality is provided by plugins. For an explanation of how plugins work, and basic information on how
+ to use a plugin, see the <a href="todo.html">introduction to plugins</a> in the Users Centre.
+ </p>
+-->
+ <p>
+ For detailed information on just some of the plugins available for Maven, see the
+ <a href="plugins/index.html">plugin list</a>.
+ </p>
+<!-- TODO: Should these be here, or just in the user centre?
+ <h3>Converting from a different Build System</h3>
+ <p>
+ If you are currently using a different build system, there are options for converting from that to Maven 2
+ either partially or completely. These guides also give an overview of the differences between Maven and the
+ other build system. The following guides are available in the Users Centre:
+ </p>
+ <ul>
+ <li><a href="todo.html">Converting from Ant to Maven 2</a></li>
+ <li><a href="todo.html">Converting from Maven 1.x to Maven 2</a></li>
+ <li><a href="todo.html">Adding Maven 2 to an IDE based build</a></li>
+ </ul>
+-->
+ <h3>How to Get Support</h3>
+ <p>
+ Support for Maven is available in a variety of different forms.
+ </p>
+ <p>
+ To get started, search the documentation, the <a href="http://docs.codehaus.org/display/MAVENUSER">wiki</a>,
+ <a href="issue-tracking.html">issue tracker</a>, or the <a href="mail-lists.html">mailing list archives</a> to
+ see if the problem has been solved or reported before.
+ </p>
+ <p>
+ If the problem has not been reported before, the recommended way to get help is to
+ subscribe to the <a href="mail-lists.html">Maven Users Mailing list</a>. Many other users and Maven developers
+ will answer your questions there, and the answer will be archived for others in the future.
+ </p>
+ <p>
+ You can also reach the Maven developers on <a href="community.html">IRC</a>.
+ </p>
+ </section>
+ </body>
+</document>
diff --git a/doxia-modules/doxia-module-xhtml5/src/test/resources/test.xhtml b/doxia-modules/doxia-module-xhtml5/src/test/resources/test.xhtml
new file mode 100644
index 0000000..e7392e5
--- /dev/null
+++ b/doxia-modules/doxia-module-xhtml5/src/test/resources/test.xhtml
@@ -0,0 +1,152 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>Title</title>
+ <meta name="author" content="Author" />
+ <meta name="date" content="Date" />
+</head>
+
+<body>
+
+<!-- MACRO{toc|fromDepth=0|toDepth=3} -->
+
+<p>Paragraph 1, line 1. Paragraph 1, line 2.</p>
+<p>Paragraph 2, line 1. Paragraph 2, line 2.</p>
+
+<section><h2>Section title</h2>
+<section><h3>Sub-section title</h3>
+<section><h4>Sub-sub-section title</h4>
+<section><h5>Sub-sub-sub-section title</h5>
+<section><h6>Sub-sub-sub-sub-section title</h6>
+
+<ul>
+ <li>List item 1.</li>
+ <li>List item 2.<p>Paragraph contained in list item 2.</p>
+ <ul>
+ <li>Sub-list item 1.</li>
+ <li>Sub-list item 2.</li>
+ </ul>
+ </li>
+ <li>List item 3. Force end of list:</li>
+</ul>
+
+<div class="source"><pre>Verbatim text not contained in list item 3</pre></div>
+
+<ol type="1">
+ <li>Numbered item 1.
+ <ol type="A">
+ <li>Numbered item A.</li>
+ <li>Numbered item B.</li>
+ </ol>
+ </li>
+ <li>Numbered item 2.</li>
+</ol>
+
+<p>List numbering schemes: [[1]], [[a]], [[A]], [[i]], [[I]].</p>
+
+<dl>
+ <dt>Defined term 1</dt>
+ <dd>of definition list.</dd>
+ <dt>Defined term 2</dt>
+ <dd>of definition list.<div class="source"><pre>Verbatim text
+ in a box </pre></div></dd>
+</dl>
+
+<p>--- instead of +-- suppresses the box around verbatim text.</p>
+
+<div class="figure">
+ <p align="center"><img src="figure.png" alt="figure.png" /></p>
+ <p align="center"><i>Figure caption</i></p>
+</div>
+
+<table align="center" border="1" class="bodyTable">
+ <caption>Table caption</caption>
+ <tr class="a">
+ <th align="center">Centered<br />cell 1,1</th>
+ <th align="left">Left-aligned<br />cell 1,2</th>
+ <th align="right">Right-aligned<br />cell 1,3</th>
+ </tr>
+ <tr class="b">
+ <td align="center">cell 2,1</td>
+ <td align="left">cell 2,2</td>
+ <td align="right">cell 2,3</td>
+ </tr>
+</table>
+
+<p>No grid, no caption:</p>
+
+<table align="center" border="0" class="bodyTable">
+ <tr class="a">
+ <td align="center">cell</td>
+ <td align="center">cell</td>
+ </tr>
+ <tr class="b">
+ <td align="center">cell</td>
+ <td align="center">cell</td>
+ </tr>
+</table>
+
+<p>Horizontal line:</p><hr />
+
+<!-- PB -->
+<p>New page.</p>
+
+<p><i>Italic</i> font. <b>Bold</b> font. <code>Monospaced</code> font.</p>
+
+<p>
+ <a name="Anchor">Anchor</a>.
+ Link to <a href="#Anchor">Anchor</a>.
+ Link to <a href="http://www.pixware.fr" class="externalLink">http://www.pixware.fr</a>.
+ Link to <a href="#Anchor">showing alternate text</a>.
+ Link to <a href="http://www.pixware.fr" class="externalLink">Pixware home page</a>.
+</p>
+
+<p>Force line<br />break.</p>
+
+<p>Non breaking space.</p>
+
+<p>Escaped special characters:<br />
+ ~<br />
+ =<br />
+ -<br />
+ +<br />
+ *<br />
+ [<br />
+ ]<br />
+ <<br />
+ ><br />
+ {<br />
+ }<br />
+ \
+</p>
+
+<p>Copyright symbol: ©, ©, ©.</p>
+
+<!-- A comment! -->
+
+</section></section></section></section></section>
+
+</body>
+
+</html>
diff --git a/doxia-modules/pom.xml b/doxia-modules/pom.xml
index 230f357..0370ead 100644
--- a/doxia-modules/pom.xml
+++ b/doxia-modules/pom.xml
@@ -45,6 +45,7 @@
<module>doxia-module-twiki</module>
<module>doxia-module-xdoc</module>
<module>doxia-module-xhtml</module>
+ <module>doxia-module-xhtml5</module>
<!-- this has a dep on xhtml module, so needs to be built last! -->
<module>doxia-module-markdown</module>
</modules>
diff --git a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
index 1b46677..f9cfd5e 100644
--- a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
+++ b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/Sink.java
@@ -318,6 +318,79 @@
void body_();
/**
+ * Starts an article within a document.
+ *
+ * @see #article(SinkEventAttributes)
+ */
+ void article();
+
+ /**
+ * Starts an article within a document.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void article( SinkEventAttributes attributes );
+
+ /**
+ * Ends the article element.
+ */
+ void article_();
+
+ /**
+ * Starts a navigation section within a document.
+ *
+ * @see #navigation(SinkEventAttributes)
+ */
+ void navigation();
+
+ /**
+ * Starts a navigation section within a document.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ * @see #navigation(SinkEventAttributes)
+ */
+ void navigation( SinkEventAttributes attributes );
+
+ /**
+ * Ends the navigation element.
+ */
+ void navigation_();
+
+ /**
+ * Starts a sidebar section within a document.
+ *
+ * @see #sidebar(SinkEventAttributes)
+ */
+ void sidebar();
+
+ /**
+ * Starts a sidebar section within a document.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void sidebar( SinkEventAttributes attributes );
+
+ /**
+ * Ends the sidebar element.
+ */
+ void sidebar_();
+
+ /**
* Starts a title heading element.
*/
void sectionTitle();
@@ -455,7 +528,7 @@
* Ends a 5th title heading element.
*/
void sectionTitle5_();
-
+
/**
* Starts a 6th heading element which contains the topic of the section.
* This has to be contained within a {@link #section5()} element.
@@ -546,6 +619,74 @@
void sectionTitle_( int level );
/**
+ * Start a new header within the section or body.
+ */
+ void header();
+
+ /**
+ * Start a new header within the section or body.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void header( SinkEventAttributes attributes );
+
+ /**
+ * Ends a header element.
+ */
+ void header_();
+
+ /**
+ * Start the main content section between the header and the
+ * footer within the sections and/or body.
+ */
+ void content();
+
+ /**
+ * Start the main content section between the header and the
+ * footer within the sections and/or body.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void content( SinkEventAttributes attributes );
+
+ /**
+ * Ends a main content section.
+ */
+ void content_();
+
+ /**
+ * Start a new footer within the section or body.
+ */
+ void footer();
+
+ /**
+ * Start a new footer within the section or body.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void footer( SinkEventAttributes attributes );
+
+ /**
+ * Ends a footer element.
+ */
+ void footer_();
+
+ /**
* Starts an unordered list element.
*
* @see #list(SinkEventAttributes)
@@ -1107,6 +1248,127 @@
void paragraph_();
/**
+ * Starts a data element which groups together other elements representing microformats.
+ *
+ * @see #data(SinkEventAttributes)
+ */
+ void data( String value );
+
+ /**
+ * Starts a data element which groups together other elements representing microformats.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}
+ * plus {@link SinkEventAttributes#VALUE VALUE}.
+ * </p>
+ *
+ * @param value the machine readable value of the data, may be <code>null</code>.
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void data( String value, SinkEventAttributes attributes );
+
+ /**
+ * Ends an data element.
+ */
+ void data_();
+
+ /**
+ * Starts a time element which groups together other elements representing a time.
+ *
+ * @see #time(SinkEventAttributes)
+ */
+ void time( String datetime );
+
+ /**
+ * Starts a time element which groups together other elements representing a time.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}
+ * plus {@link SinkEventAttributes#DATETIME DATETIME}.
+ * </p>
+ *
+ * @param datetime the machine readable value of the time, may be <code>null</code>.
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void time( String datetime, SinkEventAttributes attributes );
+
+ /**
+ * Ends a time element.
+ */
+ void time_();
+
+ /**
+ * Starts an address element.
+ *
+ * @see #address(SinkEventAttributes)
+ */
+ void address();
+
+ /**
+ * Starts an address element.
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void address( SinkEventAttributes attributes );
+
+ /**
+ * Ends an address element.
+ */
+ void address_();
+
+ /**
+ * Starts a blockquote element.
+ *
+ * @see #blockquote(SinkEventAttributes)
+ */
+ void blockquote();
+
+ /**
+ * Starts a blockquote element.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void blockquote( SinkEventAttributes attributes );
+
+ /**
+ * Ends an blockquote element.
+ */
+ void blockquote_();
+
+ /**
+ * Starts a division element grouping together other elements.
+ *
+ * @see #division(SinkEventAttributes)
+ */
+ void division();
+
+ /**
+ * Starts a division element grouping together other elements.
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes}
+ * plus {@link SinkEventAttributes#ALIGN ALIGN}.
+ * </p>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void division( SinkEventAttributes attributes );
+
+ /**
+ * Ends a division element.
+ */
+ void division_();
+
+ /**
* Starts an element which indicates that whitespace in the enclosed text has semantic relevance.
*
* @param boxed true to add a box, false otherwise
@@ -1255,6 +1517,44 @@
void link_();
/**
+ * Starts an inline element.
+ *
+ * @see #inline(String,SinkEventAttributes)
+ */
+ void inline();
+
+ /**
+ * Starts an inline element.
+ *
+ * <p>
+ * The inline method is similar to {@link #text(String,SinkEventAttributes)}, but
+ * allows you to wrap arbitrary elements in addition to text.
+ * </p>
+ *
+ * <p>
+ * Supported attributes are the {@link SinkEventAttributes base attributes} plus
+ * </p>
+ * <blockquote>
+ * {@link SinkEventAttributes#SEMANTICS SEMANTICS} (values "emphasis", "strong",
+ * "small", "line-through", "citation", "quote", "definition", "abbreviation",
+ * "italic", "bold", "monospaced", "variable", "sample", "keyboard", "superscript",
+ * "subscript", "annotation", "highlight", "ruby", "rubyBase", "rubyText",
+ * "rubyTextContainer", "rubyParentheses", "bidirectionalIsolation",
+ * "bidirectionalOverride", "phrase", "insert", "delete").
+ * </blockquote>
+ *
+ * @param text The text to write.
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void inline( SinkEventAttributes attributes );
+
+ /**
+ * Ends an inline element.
+ */
+ void inline_();
+
+ /**
* Starts an italic element.
*
* Alternatively one may use {@link #text(String,SinkEventAttributes)} with
@@ -1326,6 +1626,29 @@
void lineBreak( SinkEventAttributes attributes );
/**
+ * Adds a line break opportunity.
+ *
+ * @see #lineBreak(SinkEventAttributes)
+ */
+ void lineBreakOpportunity();
+
+ /**
+ * Adds a line break opportunity.
+ *
+ * <p>
+ * Supported attributes are:
+ * </p>
+ * <blockquote>
+ * {@link SinkEventAttributes#ID ID}, {@link SinkEventAttributes#CLASS CLASS},
+ * {@link SinkEventAttributes#TITLE TITLE}, {@link SinkEventAttributes#STYLE STYLE}.
+ * </blockquote>
+ *
+ * @param attributes A set of {@link SinkEventAttributes}, may be <code>null</code>.
+ * @since 2.0
+ */
+ void lineBreakOpportunity( SinkEventAttributes attributes );
+
+ /**
* Adding a non breaking space, <i>ie</i> a space without any special formatting operations.
*/
void nonBreakingSpace();
@@ -1354,6 +1677,17 @@
* Supported attributes are the {@link SinkEventAttributes base attributes} plus
* </p>
* <blockquote>
+ * {@link SinkEventAttributes#SEMANTICS SEMANTICS} (values "emphasis", "strong",
+ * "small", "line-through", "citation", "quote", "definition", "abbreviation",
+ * "italic", "bold", "monospaced", "variable", "sample", "keyboard", "superscript",
+ * "subscript", "annotation", "highlight", "ruby", "rubyBase", "rubyText",
+ * "rubyTextContainer", "rubyParentheses", "bidirectionalIsolation",
+ * "bidirectionalOverride", "phrase", "insert", "delete").
+ * </blockquote>
+ * <p>
+ * The following attributes are deprecated:
+ * </p>
+ * <blockquote>
* {@link SinkEventAttributes#VALIGN VALIGN} (values "sub", "sup"),
* {@link SinkEventAttributes#DECORATION DECORATION} (values "underline", "overline", "line-through"),
* {@link SinkEventAttributes#STYLE STYLE} (values "italic", "bold", "monospaced").
diff --git a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/SinkEventAttributes.java b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/SinkEventAttributes.java
index 9311220..bc3d3fc 100644
--- a/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/SinkEventAttributes.java
+++ b/doxia-sink-api/src/main/java/org/apache/maven/doxia/sink/SinkEventAttributes.java
@@ -359,4 +359,39 @@
* </p>
*/
String DECORATION = "decoration";
+
+ /**
+ * Specifies the semantics of an element.
+ *
+ * <p>
+ * Generally accepted values are "emphasis", "strong",
+ * "small", "line-through", "citation", "quote", "definition", "abbreviation",
+ * "italic", "bold", "monospaced", "code, "variable", "sample", "keyboard",
+ * "superscript", "subscript", "annotation", "highlight", "ruby", "rubyBase",
+ * "rubyText", "rubyTextContainer", "rubyParentheses", "bidirectionalIsolation",
+ * "bidirectionalOverride", "phrase", "insert", "delete".
+ * </p>
+ */
+ String SEMANTICS = "semantics";
+
+ /**
+ * Specifies the semantics of an element.
+ *
+ * <p>
+ * Generally accepted values are "article", "section",
+ * "navigation", "sidebar".
+ * </p>
+ */
+ String SECTIONS = "sections";
+
+ /**
+ * Specifies a value for the data element.
+ */
+ String VALUE = "value";
+
+ /**
+ * Specifies a machine readable date/time for the time element.
+ */
+ String DATETIME = "datetime";
+
}
diff --git a/pom.xml b/pom.xml
index 5b68025..07b4183 100644
--- a/pom.xml
+++ b/pom.xml
@@ -322,6 +322,9 @@
<exclude>org/apache/maven/doxia/module/*/*SinkFactory</exclude>
<!-- DOXIA-409 -->
<exclude>org/apache/maven/doxia/module/fo/FoUtils</exclude>
+ <!-- -->
+ <exclude>org/apache/maven/doxia/module/fml/FmlContentParser</exclude>
+ <exclude>org/apache/maven/doxia/module/xdoc/XdocParser</exclude>
</excludes>
</configuration>
</execution>