http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Table.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Table.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Table.java
index 8eb34b5..9ecac12 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Table.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Table.java
@@ -19,17 +19,17 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="table")
-@SuppressWarnings("hiding")
 public class Table extends HtmlElementContainer {
 
        /**
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/tabular-data.html#attr-table-border'>border</a>
 attribute.
         * //sortable - Enables a sorting interface for the table.
         * @param border - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Table border(String border) {
-               attrs.put("border", border);
+       public final Table border(Object border) {
+               attr("border", border);
                return this;
        }
 
@@ -38,12 +38,6 @@ public class Table extends HtmlElementContainer {
        
//--------------------------------------------------------------------------------
 
        @Override /* HtmlElement */
-       public Table children(Object...children) {
-               super.children(children);
-               return this;
-       }
-
-       @Override /* HtmlElement */
        public final Table _class(String _class) {
                super._class(_class);
                return this;
@@ -54,4 +48,16 @@ public class Table extends HtmlElementContainer {
                super.id(id);
                return this;
        }
+
+       @Override /* HtmlElementContainer */
+       public final Table children(Object...children) {
+               super.children(children);
+               return this;
+       }
+
+       @Override /* HtmlElementContainer */
+       public final Table child(Object child) {
+               super.child(child);
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tbody.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tbody.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tbody.java
index 60dc549..0612943 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tbody.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tbody.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="tbody")
-@SuppressWarnings("hiding")
 public class Tbody extends HtmlElementContainer {
 
        
//--------------------------------------------------------------------------------
@@ -27,12 +26,6 @@ public class Tbody extends HtmlElementContainer {
        
//--------------------------------------------------------------------------------
 
        @Override /* HtmlElement */
-       public Tbody children(Object...children) {
-               super.children(children);
-               return this;
-       }
-
-       @Override /* HtmlElement */
        public final Tbody _class(String _class) {
                super._class(_class);
                return this;
@@ -43,4 +36,16 @@ public class Tbody extends HtmlElementContainer {
                super.id(id);
                return this;
        }
+
+       @Override /* HtmlElementContainer */
+       public final Tbody children(Object...children) {
+               super.children(children);
+               return this;
+       }
+
+       @Override /* HtmlElementContainer */
+       public final Tbody child(Object child) {
+               super.child(child);
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Td.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Td.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Td.java
index 26b79e9..d26c845 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Td.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Td.java
@@ -19,17 +19,17 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="td")
-@SuppressWarnings("hiding")
 public class Td extends HtmlElementMixed {
 
        /**
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/tabular-data.html#attr-tdth-colspan'>colspan</a>
 attribute.
         * Number of columns that the cell is to span.
         * @param colspan - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Td colspan(String colspan) {
-               attrs.put("colspan", colspan);
+       public final Td colspan(Object colspan) {
+               attr("colspan", colspan);
                return this;
        }
 
@@ -40,7 +40,7 @@ public class Td extends HtmlElementMixed {
         * @return This object (for method chaining).
         */
        public final Td headers(String headers) {
-               attrs.put("headers", headers);
+               attr("headers", headers);
                return this;
        }
 
@@ -48,10 +48,11 @@ public class Td extends HtmlElementMixed {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/tabular-data.html#attr-tdth-rowspan'>rowspan</a>
 attribute.
         * Number of rows that the cell is to span.
         * @param rowspan - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Td rowspan(String rowspan) {
-               attrs.put("rowspan", rowspan);
+       public final Td rowspan(Object rowspan) {
+               attr("rowspan", rowspan);
                return this;
        }
 
@@ -79,7 +80,7 @@ public class Td extends HtmlElementMixed {
 
        @Override /* HtmlElementMixed */
        public Td child(Object child) {
-               this.children.add(child);
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Template.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Template.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Template.java
index a3d914a..98b77e8 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Template.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Template.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="template")
-@SuppressWarnings("hiding")
 public class Template extends HtmlElementMixed {
 
        
//--------------------------------------------------------------------------------
@@ -46,7 +45,7 @@ public class Template extends HtmlElementMixed {
 
        @Override /* HtmlElementMixed */
        public Template child(Object child) {
-               this.children.add(child);
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Textarea.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Textarea.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Textarea.java
index ec4819a..c6f9acd 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Textarea.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Textarea.java
@@ -28,7 +28,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea autocomplete(String autocomplete) {
-               attrs.put("autocomplete", autocomplete);
+               attr("autocomplete", autocomplete);
                return this;
        }
 
@@ -36,10 +36,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-fe-autofocus'>autofocus</a> 
attribute.
         * Automatically focus the form control when the page is loaded.
         * @param autofocus - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea autofocus(String autofocus) {
-               attrs.put("autofocus", autofocus);
+       public final Textarea autofocus(Boolean autofocus) {
+               attr("autofocus", autofocus);
                return this;
        }
 
@@ -47,10 +48,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-textarea-cols'>cols</a> 
attribute.
         * Maximum number of characters per line.
         * @param cols - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea cols(String cols) {
-               attrs.put("cols", cols);
+       public final Textarea cols(Object cols) {
+               attr("cols", cols);
                return this;
        }
 
@@ -61,7 +63,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea dirname(String dirname) {
-               attrs.put("dirname", dirname);
+               attr("dirname", dirname);
                return this;
        }
 
@@ -69,10 +71,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-fe-disabled'>disabled</a> 
attribute.
         * Whether the form control is disabled.
         * @param disabled - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea disabled(String disabled) {
-               attrs.put("disabled", disabled);
+       public final Textarea disabled(Object disabled) {
+               attr("disabled", disabled);
                return this;
        }
 
@@ -83,7 +86,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea form(String form) {
-               attrs.put("form", form);
+               attr("form", form);
                return this;
        }
 
@@ -94,7 +97,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea inputmode(String inputmode) {
-               attrs.put("inputmode", inputmode);
+               attr("inputmode", inputmode);
                return this;
        }
 
@@ -102,10 +105,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-textarea-maxlength'>maxlength</a>
 attribute.
         * Maximum length of value.
         * @param maxlength - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea maxlength(String maxlength) {
-               attrs.put("maxlength", maxlength);
+       public final Textarea maxlength(Object maxlength) {
+               attr("maxlength", maxlength);
                return this;
        }
 
@@ -113,10 +117,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-textarea-minlength'>minlength</a>
 attribute.
         * Minimum length of value.
         * @param minlength - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea minlength(String minlength) {
-               attrs.put("minlength", minlength);
+       public final Textarea minlength(Object minlength) {
+               attr("minlength", minlength);
                return this;
        }
 
@@ -127,7 +132,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea name(String name) {
-               attrs.put("name", name);
+               attr("name", name);
                return this;
        }
 
@@ -138,7 +143,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea placeholder(String placeholder) {
-               attrs.put("placeholder", placeholder);
+               attr("placeholder", placeholder);
                return this;
        }
 
@@ -146,10 +151,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-textarea-readonly'>readonly</a>
 attribute.
         * Whether to allow the value to be edited by the user.
         * @param readonly - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea readonly(String readonly) {
-               attrs.put("readonly", readonly);
+       public final Textarea readonly(Object readonly) {
+               attr("readonly", readonly);
                return this;
        }
 
@@ -157,10 +163,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-textarea-required'>required</a>
 attribute.
         * Whether the control is required for form submission.
         * @param required - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea required(String required) {
-               attrs.put("required", required);
+       public final Textarea required(Object required) {
+               attr("required", required);
                return this;
        }
 
@@ -168,10 +175,11 @@ public class Textarea extends HtmlElementText {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/forms.html#attr-textarea-rows'>rows</a> 
attribute.
         * Number of lines to show.
         * @param rows - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Textarea rows(String rows) {
-               attrs.put("rows", rows);
+       public final Textarea rows(Number rows) {
+               attr("rows", rows);
                return this;
        }
 
@@ -182,7 +190,7 @@ public class Textarea extends HtmlElementText {
         * @return This object (for method chaining).
         */
        public final Textarea wrap(String wrap) {
-               attrs.put("wrap", wrap);
+               attr("wrap", wrap);
                return this;
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tfoot.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tfoot.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tfoot.java
index a34478d..b4bfa19 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tfoot.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tfoot.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="tfoot")
-@SuppressWarnings("hiding")
 public class Tfoot extends HtmlElementContainer {
 
        
//--------------------------------------------------------------------------------
@@ -27,12 +26,6 @@ public class Tfoot extends HtmlElementContainer {
        
//--------------------------------------------------------------------------------
 
        @Override /* HtmlElement */
-       public Tfoot children(Object...children) {
-               super.children(children);
-               return this;
-       }
-
-       @Override /* HtmlElement */
        public final Tfoot _class(String _class) {
                super._class(_class);
                return this;
@@ -43,4 +36,16 @@ public class Tfoot extends HtmlElementContainer {
                super.id(id);
                return this;
        }
+
+       @Override /* HtmlElementContainer */
+       public final Tfoot children(Object...children) {
+               super.children(children);
+               return this;
+       }
+
+       @Override /* HtmlElementContainer */
+       public final Tfoot child(Object child) {
+               super.child(child);
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Th.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Th.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Th.java
index b05af38..500ae81 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Th.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Th.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="th")
-@SuppressWarnings("hiding")
 public class Th extends HtmlElementMixed {
 
        /**
@@ -29,7 +28,7 @@ public class Th extends HtmlElementMixed {
         * @return This object (for method chaining).
         */
        public final Th abbr(String abbr) {
-               attrs.put("abbr", abbr);
+               attr("abbr", abbr);
                return this;
        }
 
@@ -37,10 +36,11 @@ public class Th extends HtmlElementMixed {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/tabular-data.html#attr-tdth-colspan'>colspan</a>
 attribute.
         * Number of columns that the cell is to span.
         * @param colspan - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Th colspan(String colspan) {
-               attrs.put("colspan", colspan);
+       public final Th colspan(Object colspan) {
+               attr("colspan", colspan);
                return this;
        }
 
@@ -51,7 +51,7 @@ public class Th extends HtmlElementMixed {
         * @return This object (for method chaining).
         */
        public final Th headers(String headers) {
-               attrs.put("headers", headers);
+               attr("headers", headers);
                return this;
        }
 
@@ -59,10 +59,11 @@ public class Th extends HtmlElementMixed {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/tabular-data.html#attr-tdth-rowspan'>rowspan</a>
 attribute.
         * Number of rows that the cell is to span.
         * @param rowspan - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Th rowspan(String rowspan) {
-               attrs.put("rowspan", rowspan);
+       public final Th rowspan(Object rowspan) {
+               attr("rowspan", rowspan);
                return this;
        }
 
@@ -73,7 +74,7 @@ public class Th extends HtmlElementMixed {
         * @return This object (for method chaining).
         */
        public final Th scope(String scope) {
-               attrs.put("scope", scope);
+               attr("scope", scope);
                return this;
        }
 
@@ -84,7 +85,7 @@ public class Th extends HtmlElementMixed {
         * @return This object (for method chaining).
         */
        public final Th sorted(String sorted) {
-               attrs.put("sorted", sorted);
+               attr("sorted", sorted);
                return this;
        }
 
@@ -112,7 +113,7 @@ public class Th extends HtmlElementMixed {
 
        @Override /* HtmlElementMixed */
        public Th child(Object child) {
-               this.children.add(child);
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Thead.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Thead.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Thead.java
index 26cf935..231955e 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Thead.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Thead.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="thead")
-@SuppressWarnings("hiding")
 public class Thead extends HtmlElementContainer {
 
        
//--------------------------------------------------------------------------------
@@ -27,12 +26,6 @@ public class Thead extends HtmlElementContainer {
        
//--------------------------------------------------------------------------------
 
        @Override /* HtmlElement */
-       public Thead children(Object...children) {
-               super.children(children);
-               return this;
-       }
-
-       @Override /* HtmlElement */
        public final Thead _class(String _class) {
                super._class(_class);
                return this;
@@ -43,4 +36,16 @@ public class Thead extends HtmlElementContainer {
                super.id(id);
                return this;
        }
+
+       @Override /* HtmlElementContainer */
+       public final Thead children(Object...children) {
+               super.children(children);
+               return this;
+       }
+
+       @Override /* HtmlElementContainer */
+       public final Thead child(Object child) {
+               super.child(child);
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Time.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Time.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Time.java
index 48a736e..3a176b3 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Time.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Time.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="time")
-@SuppressWarnings("hiding")
 public class Time extends HtmlElementMixed {
 
        /**
@@ -29,7 +28,7 @@ public class Time extends HtmlElementMixed {
         * @return This object (for method chaining).
         */
        public final Time datetime(String datetime) {
-               attrs.put("datetime", datetime);
+               attr("datetime", datetime);
                return this;
        }
 
@@ -57,7 +56,7 @@ public class Time extends HtmlElementMixed {
 
        @Override /* HtmlElementMixed */
        public Time child(Object child) {
-               this.children.add(child);
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tr.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tr.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tr.java
index 4a0dd10..e3ed4ad 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tr.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Tr.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="tr")
-@SuppressWarnings("hiding")
 public class Tr extends HtmlElementContainer {
 
        
//--------------------------------------------------------------------------------
@@ -27,12 +26,6 @@ public class Tr extends HtmlElementContainer {
        
//--------------------------------------------------------------------------------
 
        @Override /* HtmlElement */
-       public Tr children(Object...children) {
-               super.children(children);
-               return this;
-       }
-
-       @Override /* HtmlElement */
        public final Tr _class(String _class) {
                super._class(_class);
                return this;
@@ -43,4 +36,16 @@ public class Tr extends HtmlElementContainer {
                super.id(id);
                return this;
        }
+
+       @Override /* HtmlElementContainer */
+       public final Tr children(Object...children) {
+               super.children(children);
+               return this;
+       }
+
+       @Override /* HtmlElementContainer */
+       public final Tr child(Object child) {
+               super.child(child);
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Track.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Track.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Track.java
index fc10b7d..2c02600 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Track.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Track.java
@@ -12,6 +12,8 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.dto.html5;
 
+import java.net.*;
+
 import org.apache.juneau.annotation.*;
 
 /**
@@ -28,7 +30,7 @@ public class Track extends HtmlElementEmpty {
         * @return This object (for method chaining).
         */
        public final Track _default(String _default) {
-               attrs.put("default", _default);
+               attr("default", _default);
                return this;
        }
 
@@ -39,7 +41,7 @@ public class Track extends HtmlElementEmpty {
         * @return This object (for method chaining).
         */
        public final Track kind(String kind) {
-               attrs.put("kind", kind);
+               attr("kind", kind);
                return this;
        }
 
@@ -50,7 +52,7 @@ public class Track extends HtmlElementEmpty {
         * @return This object (for method chaining).
         */
        public final Track label(String label) {
-               attrs.put("label", label);
+               attr("label", label);
                return this;
        }
 
@@ -58,10 +60,11 @@ public class Track extends HtmlElementEmpty {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-track-src'>src</a>
 attribute.
         * Address of the resource.
         * @param src - The new value for this attribute.
+        *      Typically a {@link URL} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Track src(String src) {
-               attrs.put("src", src);
+       public final Track src(Object src) {
+               attr("src", src);
                return this;
        }
 
@@ -72,7 +75,7 @@ public class Track extends HtmlElementEmpty {
         * @return This object (for method chaining).
         */
        public final Track srclang(String srclang) {
-               attrs.put("srclang", srclang);
+               attr("srclang", srclang);
                return this;
        }
 

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/U.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/U.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/U.java
index 20b5c07..2e1774f 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/U.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/U.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="u")
-@SuppressWarnings("hiding")
 public class U extends HtmlElementMixed {
 
        
//--------------------------------------------------------------------------------
@@ -46,7 +45,7 @@ public class U extends HtmlElementMixed {
 
        @Override /* HtmlElementMixed */
        public U child(Object child) {
-               this.children.add(child);
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Ul.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Ul.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Ul.java
index 014254f..8b6c129 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Ul.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Ul.java
@@ -19,8 +19,7 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="ul")
-@SuppressWarnings("hiding")
-public class Ul extends HtmlElementMixed {
+public class Ul extends HtmlElementContainer {
 
        
//--------------------------------------------------------------------------------
        // Overridden methods
@@ -38,15 +37,15 @@ public class Ul extends HtmlElementMixed {
                return this;
        }
 
-       @Override /* HtmlElementMixed */
-       public Ul children(Object...children) {
+       @Override /* HtmlElementContainer */
+       public final Ul children(Object...children) {
                super.children(children);
                return this;
        }
 
-       @Override /* HtmlElementMixed */
-       public Ul child(Object child) {
-               this.children.add(child);
+       @Override /* HtmlElementContainer */
+       public final Ul child(Object child) {
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Var.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Var.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Var.java
index 11464f2..69361a7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Var.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Var.java
@@ -19,7 +19,6 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="var")
-@SuppressWarnings("hiding")
 public class Var extends HtmlElementMixed {
 
        
//--------------------------------------------------------------------------------
@@ -46,7 +45,7 @@ public class Var extends HtmlElementMixed {
 
        @Override /* HtmlElementMixed */
        public Var child(Object child) {
-               this.children.add(child);
+               super.child(child);
                return this;
        }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/Video.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Video.java 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Video.java
index f92ccd4..23ac865 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/Video.java
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/Video.java
@@ -12,6 +12,8 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.dto.html5;
 
+import java.net.*;
+
 import org.apache.juneau.annotation.*;
 
 /**
@@ -19,16 +21,17 @@ import org.apache.juneau.annotation.*;
  * <p>
  */
 @Bean(typeName="video")
-public class Video extends HtmlElement {
+public class Video extends HtmlElementContainer {
 
        /**
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-autoplay'>autoplay</a>
 attribute.
         * Hint that the media resource can be started automatically when the 
page is loaded.
         * @param autoplay - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video autoplay(String autoplay) {
-               attrs.put("autoplay", autoplay);
+       public final Video autoplay(Object autoplay) {
+               attr("autoplay", autoplay);
                return this;
        }
 
@@ -36,10 +39,11 @@ public class Video extends HtmlElement {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-controls'>controls</a>
 attribute.
         * Show user agent controls.
         * @param controls - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video controls(String controls) {
-               attrs.put("controls", controls);
+       public final Video controls(Object controls) {
+               attr("controls", controls);
                return this;
        }
 
@@ -50,7 +54,7 @@ public class Video extends HtmlElement {
         * @return This object (for method chaining).
         */
        public final Video crossorigin(String crossorigin) {
-               attrs.put("crossorigin", crossorigin);
+               attr("crossorigin", crossorigin);
                return this;
        }
 
@@ -58,10 +62,11 @@ public class Video extends HtmlElement {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-dim-height'>height</a>
 attribute.
         * Vertical dimension.
         * @param height - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video height(String height) {
-               attrs.put("height", height);
+       public final Video height(Object height) {
+               attr("height", height);
                return this;
        }
 
@@ -69,10 +74,11 @@ public class Video extends HtmlElement {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-loop'>loop</a>
 attribute.
         * Whether to loop the media resource.
         * @param loop - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video loop(String loop) {
-               attrs.put("loop", loop);
+       public final Video loop(Object loop) {
+               attr("loop", loop);
                return this;
        }
 
@@ -83,7 +89,7 @@ public class Video extends HtmlElement {
         * @return This object (for method chaining).
         */
        public final Video mediagroup(String mediagroup) {
-               attrs.put("mediagroup", mediagroup);
+               attr("mediagroup", mediagroup);
                return this;
        }
 
@@ -91,10 +97,11 @@ public class Video extends HtmlElement {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-muted'>muted</a>
 attribute.
         * Whether to mute the media resource by default.
         * @param muted - The new value for this attribute.
+        *      Typically a {@link Boolean} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video muted(String muted) {
-               attrs.put("muted", muted);
+       public final Video muted(Object muted) {
+               attr("muted", muted);
                return this;
        }
 
@@ -105,7 +112,7 @@ public class Video extends HtmlElement {
         * @return This object (for method chaining).
         */
        public final Video poster(String poster) {
-               attrs.put("poster", poster);
+               attr("poster", poster);
                return this;
        }
 
@@ -116,7 +123,7 @@ public class Video extends HtmlElement {
         * @return This object (for method chaining).
         */
        public final Video preload(String preload) {
-               attrs.put("preload", preload);
+               attr("preload", preload);
                return this;
        }
 
@@ -124,10 +131,11 @@ public class Video extends HtmlElement {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-media-src'>src</a>
 attribute.
         * Address of the resource.
         * @param src - The new value for this attribute.
+        *      Typically a {@link URL} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video src(String src) {
-               attrs.put("src", src);
+       public final Video src(Object src) {
+               attr("src", src);
                return this;
        }
 
@@ -135,10 +143,11 @@ public class Video extends HtmlElement {
         * <a class='doclink' 
href='https://www.w3.org/TR/html5/embedded-content-0.html#attr-dim-width'>width</a>
 attribute.
         * Horizontal dimension.
         * @param width - The new value for this attribute.
+        *      Typically a {@link Number} or {@link String}.
         * @return This object (for method chaining).
         */
-       public final Video width(String width) {
-               attrs.put("width", width);
+       public final Video width(Object width) {
+               attr("width", width);
                return this;
        }
 
@@ -157,4 +166,16 @@ public class Video extends HtmlElement {
                super.id(id);
                return this;
        }
+
+       @Override /* HtmlElementContainer */
+       public final Video children(Object...children) {
+               super.children(children);
+               return this;
+       }
+
+       @Override /* HtmlElementContainer */
+       public final Video child(Object child) {
+               super.child(child);
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/dto/html5/package.html
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/dto/html5/package.html 
b/juneau-core/src/main/java/org/apache/juneau/dto/html5/package.html
index a721d71..f5b39d9 100644
--- a/juneau-core/src/main/java/org/apache/juneau/dto/html5/package.html
+++ b/juneau-core/src/main/java/org/apache/juneau/dto/html5/package.html
@@ -36,6 +36,160 @@
        </script>
 </head>
 <body>
-<p>HTML Data Transfer Objects</p>
+<p>HTML5 Data Transfer Objects</p>
+<script>
+       function toggle(x) {
+               var div = x.nextSibling;
+               while (div != null && div.nodeType != 1)
+                       div = div.nextSibling;
+               if (div != null) {
+                       var d = div.style.display;
+                       if (d == 'block' || d == '') {
+                               div.style.display = 'none';
+                               x.className += " closed";
+                       } else {
+                               div.style.display = 'block';
+                               x.className = 
x.className.replace(/(?:^|\s)closed(?!\S)/g , '' );
+                       }
+               }
+       }
+</script>
+<a id='TOC'></a><h5 class='toc'>Table of Contents</h5>
+<ol class='toc'>
+       <li><p><a class='doclink' href='#Overview'>Overview</a></p>
+       <ol>
+               <li><p><a class='doclink' href='#Serialize'>Generating 
HTML5</a></p>
+               <li><p><a class='doclink' href='#Parse'>Parsing HTML5</a></p>
+       </ol>
+</ol>
+
+
+<!-- 
========================================================================================================
 -->
+<a id="Overview"></a>
+<h2 class='topic' onclick='toggle(this)'>1 - Overview</h2>
+<div class='topic'>
+       <p>
+               Juneau supports generation and consumption of HTML5 documents 
and fragments through the use of DTOs (Data Transfer Objects).<br>
+               It uses existing support for serializing and parsing POJOs to 
and from HTML to define these HTML objects. 
+       </p>
+       
+       
+       <!-- 
========================================================================================================
 -->
+       <a id="Serialize"></a>
+       <h3 class='topic' onclick='toggle(this)'>1.1 - Generating HTML5</h3>
+       <div class='topic'>
+               <p>
+                       The Juneau HTML5 DTOs are simply beans with 
fluent-style setters that allow you to quickly construct HTML
+                       fragments as Java objects.  These object can then be 
serialized to HTML using one of the existing HTML serializers,
+                       or to other languages such as JSON using the JSON 
serializers.
+               </p>
+               <p>
+                       The {@link org.apache.juneau.dto.html5.HtmlBuilder} 
class is a utility class with predefined static methods
+                       that allow you to easily construct DTO instances in a 
minimal amount of code. 
+               </p>
+               <p>
+                       The following examples show how to create HTML tables.
+               </p>
+               <table class='styled' style='width:auto'>
+                       <tr>
+                               <th>Java code</th>
+                               <th>HTML</th>
+                       </tr>
+                       <tr>
+                               <td class='code'>
+       <jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
+       
+       Object mytable =        
+               table(
+                       tr(th(<js>"c1"</js>),th(<js>"c2"</js>)),
+                       tr(td(<js>"v1"</js>),td(<js>"v2"</js>))
+               );
+
+       String html = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(mytable);
+                               </td>
+                               <td class='code'><xt>
+       &lt;table&gt;
+               &lt;tr&gt;
+                       &lt;th&gt;<xv>c1</xv>&lt;/th&gt;
+                       &lt;th&gt;<xv>c2</xv>&lt;/th&gt;
+               &lt;/tr&gt;
+               &lt;tr&gt;
+                       &lt;td&gt;<xv>v1</xv>&lt;/td&gt;
+                       &lt;td&gt;<xv>v2</xv>&lt;/td&gt;
+               &lt;/tr&gt;
+       &lt;/table&gt;
+                               </xt></td>
+                       </tr>
+                       <tr>
+                               <td class='code'>
+       <jk>import static</jk> org.apache.juneau.dto.html5.HtmlBuilder.*;
+       
+       Object mytable =        
+               table(
+                       caption(<js>"mytable"</js>),
+                       colgroup(
+                               col()._class(<js>"foo"</js>),
+                               col()._class(<js>"bar"</js>)
+                       ),
+                       thead(tr(th(<js>"c1"</js>),th(<js>"c2"</js>))),
+                       tbody(tr(td(<js>"v1"</js>),td(<js>"v2"</js>))),
+                       tfoot(tr(td(<js>"f1"</js>),td(<js>"f2"</js>)))
+               );
+
+       String html = HtmlSerializer.<jsf>DEFAULT</jsf>.serialize(mytable);
+                               </td>
+                               <td class='code'><xt>
+       &lt;table&gt;
+               &lt;caption&gt;<xv>mytable</xv>&lt;/caption&gt;
+               &lt;colgroup&gt;
+                       &lt;col <xa>class</xa>=<xs>'foo'</xs>/&gt;
+                       &lt;col <xa>class</xa>=<xs>'bar'</xs>/&gt;
+               &lt;/colgroup&gt;
+               &lt;thead&gt;
+                       &lt;tr&gt;
+                               &lt;th&gt;<xv>c1</xv>&lt;/th&gt;
+                               &lt;th&gt;<xv>c2</xv>&lt;/th&gt;
+                       &lt;/tr&gt;
+               &lt;/thead&gt;
+               &lt;tbody&gt;
+                       &lt;tr&gt;
+                               &lt;td&gt;<xv>v1</xv>&lt;/td&gt;
+                               &lt;td&gt;<xv>v2</xv>&lt;/td&gt;
+                       &lt;/tr&gt;
+               &lt;/tbody&gt;
+               &lt;tfoot&gt;
+                       &lt;tr&gt;
+                               &lt;td&gt;<xv>f1</xv>&lt;/td&gt;
+                               &lt;td&gt;<xv>f2</xv>&lt;/td&gt;
+                       &lt;/tr&gt;
+               &lt;/tfoot&gt;
+       &lt;/table&gt;
+                               </xt></td>
+                       </tr>
+               </table>
+</div>         
+
+       <!-- 
========================================================================================================
 -->
+       <a id="Parse"></a>
+       <h3 class='topic' onclick='toggle(this)'>1.2 - Parsing HTML5</h3>
+       <div class='topic'>
+               <p>
+                       Use the {@link org.apache.juneau.xml.HtmlParser} to 
convert HTML5 documents back into their original POJOs:
+               </p>
+               <p class='bcode'>
+       <jc>// Get an HTML parser to convert our generated HTML5 documents back 
into POJOs.</jc>
+       HtmlParser p = HtmlParser.<jsf>DEFAULT</jsf>;
+       
+       <jc>// Convert an HTML table back into a Table object.</jc>
+       Table table = p.parse(tableHtml, Table.<jk>class</jk>);
+               </p>
+               <p>
+                       HTML5 objects can also be constructed from the other 
media types using the appropriate parsers.
+               </p>
+       </div>
+
+</div>
+<p align="center"><i><b>*** fín ***</b></i></p>
+
 </body>
 </html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
index 7a4d6dd..badac2a 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlDocSerializer.java
@@ -101,9 +101,9 @@ public class HtmlDocSerializer extends 
HtmlStrippedDocSerializer {
                        title = "Options";
                String description = s.getDescription();
                if (title != null)
-                       w.oTag(1, "h3").attr("class", 
"title").append('>').encodeText(title).eTag("h3").nl();
+                       w.oTag(1, "h3").attr("class", 
"title").append('>').text(title).eTag("h3").nl();
                if (description != null)
-                       w.oTag(1, "h5").attr("class", 
"description").append('>').encodeText(description).eTag("h5").nl();
+                       w.oTag(1, "h5").attr("class", 
"description").append('>').text(description).eTag("h5").nl();
 
                // Write the action links that render above the results.
                List<Link> actions = new LinkedList<Link>();

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
index f2fd9e0..4afe08c 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParser.java
@@ -13,7 +13,7 @@
 package org.apache.juneau.html;
 
 import static javax.xml.stream.XMLStreamConstants.*;
-import static org.apache.juneau.html.HtmlParser.Tag.*;
+import static org.apache.juneau.html.HtmlTag.*;
 import static org.apache.juneau.internal.StringUtils.*;
 
 import java.lang.reflect.*;
@@ -93,12 +93,12 @@ public final class HtmlParser extends XmlParser {
                Object o = null;
 
                boolean isValid = true;
-               Tag tag = (event == CHARACTERS ? null : 
Tag.forString(r.getName().getLocalPart(), false));
+               HtmlTag tag = (event == CHARACTERS ? null : 
HtmlTag.forString(r.getName().getLocalPart(), false));
 
                if (isEmpty) {
                        o = "";
-               } else if (tag == null || tag.isOneOf(BR,BS,TB,FF)) {
-                       String text = parseCharacters(session, r);
+               } else if (tag == null || tag.isOneOf(BR,BS,FF,SP)) {
+                       String text = session.parseText(r);
                        if (sType.isObject() || sType.isCharSequence())
                                o = text;
                        else if (sType.isChar())
@@ -115,7 +115,7 @@ public final class HtmlParser extends XmlParser {
                                isValid = false;
 
                } else if (tag == STRING) {
-                       String text = parseElementText(session, r);
+                       String text = session.getElementText(r);
                        if (sType.isObject() || sType.isCharSequence())
                                o = text;
                        else if (sType.isChar())
@@ -129,7 +129,7 @@ public final class HtmlParser extends XmlParser {
                        skipTag(r, xSTRING);
 
                } else if (tag == NUMBER) {
-                       String text = parseElementText(session, r);
+                       String text = session.getElementText(r);
                        if (sType.isObject())
                                o = parseNumber(text, Number.class);
                        else if (sType.isNumber())
@@ -141,7 +141,7 @@ public final class HtmlParser extends XmlParser {
                        skipTag(r, xNUMBER);
 
                } else if (tag == BOOLEAN) {
-                       String text = parseElementText(session, r);
+                       String text = session.getElementText(r);
                        if (sType.isObject() || sType.isBoolean())
                                o = Boolean.parseBoolean(text);
                        else
@@ -245,7 +245,7 @@ public final class HtmlParser extends XmlParser {
         */
        private <T> T parseAnchor(HtmlParserSession session, XMLStreamReader r, 
ClassMeta<T> beanType) throws XMLStreamException {
                String href = r.getAttributeValue(null, "href");
-               String name = parseElementText(session, r);
+               String name = session.getElementText(r);
                Class<T> beanClass = beanType.getInnerClass();
                if (beanClass.isAnnotationPresent(HtmlLink.class)) {
                        HtmlLink h = beanClass.getAnnotation(HtmlLink.class);
@@ -271,23 +271,22 @@ public final class HtmlParser extends XmlParser {
         */
        private <K,V> Map<K,V> parseIntoMap(HtmlParserSession session, 
XMLStreamReader r, Map<K,V> m, ClassMeta<K> keyType, ClassMeta<V> valueType, 
BeanPropertyMeta pMeta) throws Exception {
                while (true) {
-                       Tag tag = nextTag(r, TR, xTABLE);
+                       HtmlTag tag = nextTag(r, TR, xTABLE);
                        if (tag == xTABLE)
                                break;
                        tag = nextTag(r, TD, TH);
                        // Skip over the column headers.
                        if (tag == TH) {
-                               skipElementText(r);
-                               nextTag(r, TH);
-                               skipElementText(r);
-                               nextTag(r, xTR);
-                               continue;
+                               skipTag(r);
+                               r.nextTag();
+                               skipTag(r);
+                       } else {
+                               K key = parseAnything(session, keyType, r, m, 
false, pMeta);
+                               nextTag(r, TD);
+                               V value = parseAnything(session, valueType, r, 
m, false, pMeta);
+                               setName(valueType, value, key);
+                               m.put(key, value);
                        }
-                       K key = parseAnything(session, keyType, r, m, false, 
pMeta);
-                       nextTag(r, TD);
-                       V value = parseAnything(session, valueType, r, m, 
false, pMeta);
-                       setName(valueType, value, key);
-                       m.put(key, value);
                        nextTag(r, xTR);
                }
 
@@ -301,7 +300,7 @@ public final class HtmlParser extends XmlParser {
         */
        private <E> Collection<E> parseIntoCollection(HtmlParserSession 
session, XMLStreamReader r, Collection<E> l, ClassMeta<E> elementType, 
BeanPropertyMeta pMeta) throws Exception {
                while (true) {
-                       Tag tag = nextTag(r, LI, xUL);
+                       HtmlTag tag = nextTag(r, LI, xUL);
                        if (tag == xUL)
                                break;
                        l.add(parseAnything(session, elementType, r, l, false, 
pMeta));
@@ -318,7 +317,7 @@ public final class HtmlParser extends XmlParser {
                Object[] o = new Object[argTypes.length];
                int i = 0;
                while (true) {
-                       Tag tag = nextTag(r, LI, xUL);
+                       HtmlTag tag = nextTag(r, LI, xUL);
                        if (tag == xUL)
                                break;
                        o[i] = parseAnything(session, argTypes[i], r, 
session.getOuter(), false, null);
@@ -338,18 +337,18 @@ public final class HtmlParser extends XmlParser {
                        elementType = (ClassMeta<E>)object();
                BeanRegistry breg = (pMeta == null ? session.getBeanRegistry() 
: pMeta.getBeanRegistry());
 
-               Tag tag = nextTag(r, TR);
+               HtmlTag tag = nextTag(r, TR);
                List<String> keys = new ArrayList<String>();
                while (true) {
                        tag = nextTag(r, TH, xTR);
                        if (tag == xTR)
                                break;
-                       keys.add(parseElementText(session, r));
+                       keys.add(session.getElementText(r));
                }
 
                while (true) {
                        r.nextTag();
-                       tag = Tag.forEvent(r);
+                       tag = HtmlTag.forEvent(r);
                        if (tag == xTABLE)
                                break;
 
@@ -419,34 +418,33 @@ public final class HtmlParser extends XmlParser {
         */
        private <T> BeanMap<T> parseIntoBean(HtmlParserSession session, 
XMLStreamReader r, BeanMap<T> m) throws Exception {
                while (true) {
-                       Tag tag = nextTag(r, TR, xTABLE);
+                       HtmlTag tag = nextTag(r, TR, xTABLE);
                        if (tag == xTABLE)
                                break;
                        tag = nextTag(r, TD, TH);
                        // Skip over the column headers.
                        if (tag == TH) {
-                               skipElementText(r);
-                               nextTag(r, TH);
-                               skipElementText(r);
-                               nextTag(r, xTR);
-                               continue;
-                       }
-                       String key = parseElementText(session, r);
-                       nextTag(r, TD);
-                       BeanPropertyMeta pMeta = m.getPropertyMeta(key);
-                       if (pMeta == null) {
-                               if (m.getMeta().isSubTyped()) {
-                                       Object value = parseAnything(session, 
object(), r, m.getBean(false), false, null);
-                                       m.put(key, value);
+                               skipTag(r);
+                               r.nextTag();
+                               skipTag(r);
+                       } else {
+                               String key = session.getElementText(r);
+                               nextTag(r, TD);
+                               BeanPropertyMeta pMeta = m.getPropertyMeta(key);
+                               if (pMeta == null) {
+                                       if (m.getMeta().isSubTyped()) {
+                                               Object value = 
parseAnything(session, object(), r, m.getBean(false), false, null);
+                                               m.put(key, value);
+                                       } else {
+                                               onUnknownProperty(session, key, 
m, -1, -1);
+                                               parseAnything(session, 
object(), r, null, false, null);
+                                       }
                                } else {
-                                       onUnknownProperty(session, key, m, -1, 
-1);
-                                       parseAnything(session, object(), r, 
null, false, null);
+                                       ClassMeta<?> cm = pMeta.getClassMeta();
+                                       Object value = parseAnything(session, 
cm, r, m.getBean(false), false, pMeta);
+                                       setName(cm, value, key);
+                                       pMeta.set(m, value);
                                }
-                       } else {
-                               ClassMeta<?> cm = pMeta.getClassMeta();
-                               Object value = parseAnything(session, cm, r, 
m.getBean(false), false, pMeta);
-                               setName(cm, value, key);
-                               pMeta.set(m, value);
                        }
                        nextTag(r, xTR);
                }
@@ -454,195 +452,6 @@ public final class HtmlParser extends XmlParser {
        }
 
 
-       /*
-        * Parse until the next event is an end tag.
-        */
-       private String parseCharacters(HtmlParserSession session, 
XMLStreamReader r) throws XMLStreamException {
-
-               StringBuilder sb = session.getStringBuilder();
-
-               int et = r.getEventType();
-               int depth = (et == START_ELEMENT ? 1 : et == END_ELEMENT ? -1 : 
0);
-
-               while (depth >= 0) {
-                       if (et == START_ELEMENT) {
-                               Tag tag = Tag.forEvent(r);
-                               if (tag == BR) {
-                                       sb.append("\n");
-                               } else if (tag == BS) {
-                                       sb.append("\b");
-                               } else if (tag == TB) {
-                                       sb.append("\t");
-                                       r.next();
-                               } else if (tag == FF) {
-                                       sb.append("\f");
-                               } else if (! tag.isOneOf(STRING, NUMBER, 
BOOLEAN)) {
-                                       sb.append('<').append(r.getLocalName());
-                                       for (int i = 0; i < 
r.getAttributeCount(); i++)
-                                               sb.append(' 
').append(r.getAttributeName(i)).append('=').append('\'').append(r.getAttributeValue(i)).append('\'');
-                                       sb.append('>');
-                               }
-                       } else if (et == END_ELEMENT) {
-                               Tag tag = Tag.forEvent(r);
-                               if (! tag.isOneOf(xBR, xBS, xTB, xFF, xSTRING, 
xNUMBER, xBOOLEAN)) {
-                                       
sb.append('<').append(r.getLocalName()).append('>');
-                               }
-                       } else if (et == CHARACTERS && ! r.isWhiteSpace()) {
-                               sb.append(r.getText().trim());
-                       }
-                       et = r.next();
-                       if (et == START_ELEMENT)
-                               depth++;
-                       else if (et == END_ELEMENT)
-                               depth--;
-               }
-
-               String s = sb.toString();
-               session.returnStringBuilder(sb);
-               return s;
-       }
-
-       private void skipCharacters(XMLStreamReader r) throws 
XMLStreamException {
-
-               int et = r.getEventType();
-
-               int depth = (et == START_ELEMENT ? 1 : et == END_ELEMENT ? -1 : 
0);
-               while (depth >= 0) {
-                       et = r.next();
-                       if (et == START_ELEMENT)
-                               depth++;
-                       else if (et == END_ELEMENT)
-                               depth--;
-               }
-       }
-
-       /*
-        * Reads the element text of the current element, accounting for <a> 
and <br> tags.
-        * Precondition:  Must be pointing at parent START_ELEMENT tag.
-        * Postcondition:  Pointing at next START_ELEMENT or END_DOCUMENT event.
-        */
-       private String parseElementText(HtmlParserSession session, 
XMLStreamReader r/*, Tag endTag*/) throws XMLStreamException {
-               r.next();
-               return parseCharacters(session, r);
-       }
-
-       private void skipElementText(XMLStreamReader r) throws 
XMLStreamException {
-               r.next();
-               skipCharacters(r);
-       }
-
-       enum Tag {
-
-               TABLE(1,"<table>"),
-               TR(2,"<tr>"),
-               TH(3,"<th>"),
-               TD(4,"<td>"),
-               UL(5,"<ul>"),
-               LI(6,"<li>"),
-               STRING(7,"<string>"),
-               NUMBER(8,"<number>"),
-               BOOLEAN(9,"<boolean>"),
-               NULL(10,"<null>"),
-               A(11,"<a>"),
-               BR(12,"<br>"),          // newline
-               FF(13,"<ff>"),          // formfeed
-               BS(14,"<bs>"),          // backspace
-               TB(15,"<tb>"),          // tab
-               xTABLE(-1,"</table>"),
-               xTR(-2,"</tr>"),
-               xTH(-3,"</th>"),
-               xTD(-4,"</td>"),
-               xUL(-5,"</ul>"),
-               xLI(-6,"</li>"),
-               xSTRING(-7,"</string>"),
-               xNUMBER(-8,"</number>"),
-               xBOOLEAN(-9,"</boolean>"),
-               xNULL(-10,"</null>"),
-               xA(-11,"</a>"),
-               xBR(-12,"</br>"),
-               xFF(-13,"</ff>"),
-               xBS(-14,"</bs>"),
-               xTB(-15,"</tb>");
-
-               private Map<Integer,Tag> cache = new HashMap<Integer,Tag>();
-
-               int id;
-               String label;
-
-               Tag(int id, String label) {
-                       this.id = id;
-                       this.label = label;
-                       cache.put(id, this);
-               }
-
-               static Tag forEvent(XMLStreamReader r) throws 
XMLStreamException {
-                       int et = r.getEventType();
-                       if (et == START_ELEMENT)
-                               return forString(r.getLocalName(), false);
-                       else if (et == END_ELEMENT)
-                               return forString(r.getLocalName(), true);
-                       throw new XMLStreamException("Invalid call to 
Tag.forEvent on event of type ["+et+"]");
-               }
-
-               private static Tag forString(String tag, boolean end) throws 
XMLStreamException {
-                       char c = tag.charAt(0);
-                       Tag t = null;
-                       if (c == 'u')
-                               t = (end ? xUL : UL);
-                       else if (c == 'l')
-                               t = (end ? xLI : LI);
-                       else if (c == 's')
-                               t = (end ? xSTRING : STRING);
-                       else if (c == 'b') {
-                               c = tag.charAt(1);
-                               if (c == 'o')
-                                       t = (end ? xBOOLEAN : BOOLEAN);
-                               else if (c == 'r')
-                                       t = (end ? xBR : BR);
-                               else if (c == 's')
-                                       t = (end ? xBS : BS);
-                       }
-                       else if (c == 'a')
-                               t = (end ? xA : A);
-                       else if (c == 'n') {
-                               c = tag.charAt(2);
-                               if (c == 'm')
-                                       t = (end ? xNUMBER : NUMBER);
-                               else if (c == 'l')
-                                       t = (end ? xNULL : NULL);
-                       }
-                       else if (c == 't') {
-                               c = tag.charAt(1);
-                               if (c == 'a')
-                                       t = (end ? xTABLE : TABLE);
-                               else if (c == 'r')
-                                       t = (end ? xTR : TR);
-                               else if (c == 'h')
-                                       t = (end ? xTH : TH);
-                               else if (c == 'd')
-                                       t = (end ? xTD : TD);
-                               else if (c == 'b')
-                                       t = (end ? xTB : TB);
-                       }
-                       else if (c == 'f')
-                               t = (end ? xFF : FF);
-                       if (t == null)
-                               throw new XMLStreamException("Unknown tag 
'"+tag+"' encountered");
-                       return t;
-               }
-
-               @Override /* Object */
-               public String toString() {
-                       return label;
-               }
-
-               public boolean isOneOf(Tag...tags) {
-                       for (Tag tag : tags)
-                               if (tag == this)
-                                       return true;
-                       return false;
-               }
-       }
 
        /*
         * Reads the next tag.  Advances past anything that's not a start or 
end tag.  Throws an exception if
@@ -650,7 +459,7 @@ public final class HtmlParser extends XmlParser {
         * Precondition:  Must be pointing before the event we want to parse.
         * Postcondition:  Pointing at the tag just parsed.
         */
-       private Tag nextTag(XMLStreamReader r, Tag...expected) throws 
XMLStreamException {
+       private HtmlTag nextTag(XMLStreamReader r, HtmlTag...expected) throws 
XMLStreamException {
                int et = r.next();
 
                while (et != START_ELEMENT && et != END_ELEMENT && et != 
END_DOCUMENT)
@@ -659,25 +468,58 @@ public final class HtmlParser extends XmlParser {
                if (et == END_DOCUMENT)
                        throw new XMLStreamException("Unexpected end of 
document: " + r.getLocation());
 
-               Tag tag = Tag.forEvent(r);
+               HtmlTag tag = HtmlTag.forEvent(r);
                if (expected.length == 0)
                        return tag;
-               for (Tag t : expected)
+               for (HtmlTag t : expected)
                        if (t == tag)
                                return tag;
 
                throw new XMLStreamException("Unexpected tag: " + tag + ".  
Expected one of the following: " + JsonSerializer.DEFAULT.toString(expected), 
r.getLocation());
        }
 
-       private void skipTag(XMLStreamReader r, Tag...expected) throws 
XMLStreamException {
-               Tag tag = Tag.forEvent(r);
+       /**
+        * Skips over the current element and advances to the next element.
+        * <p>
+        * Precondition:  Pointing to opening tag.
+        * Postcondition:  Pointing to next opening tag.
+        *
+        * @param r The stream being read from.
+        * @throws XMLStreamException
+        */
+       private void skipTag(XMLStreamReader r) throws XMLStreamException {
+               int et = r.getEventType();
+
+               if (et != START_ELEMENT)
+                       throw new XMLStreamException("skipToNextTag() call on 
invalid event ["+XmlUtils.toReadableEvent(r)+"].  Must only be called on 
START_ELEMENT events.");
+
+               String n = r.getLocalName();
+
+               int depth = 0;
+               while (true) {
+                       et = r.next();
+                       if (et == START_ELEMENT) {
+                               String n2 = r.getLocalName();
+                                       if (n.equals(n2))
+                               depth++;
+                       } else if (et == END_ELEMENT) {
+                               String n2 = r.getLocalName();
+                               if (n.equals(n2))
+                                       depth--;
+                               if (depth < 0)
+                                       return;
+                       }
+               }
+       }
+
+       private void skipTag(XMLStreamReader r, HtmlTag...expected) throws 
XMLStreamException {
+               HtmlTag tag = HtmlTag.forEvent(r);
                if (tag.isOneOf(expected))
                        r.next();
                else
                        throw new XMLStreamException("Unexpected tag: " + tag + 
".  Expected one of the following: " + 
JsonSerializer.DEFAULT.toString(expected), r.getLocation());
        }
 
-
        private int skipWs(XMLStreamReader r)  throws XMLStreamException {
                int event = r.getEventType();
                while (event != START_ELEMENT && event != END_ELEMENT && event 
!= END_DOCUMENT && r.isWhiteSpace())

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index 5d3c3bf..95febd7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -12,6 +12,9 @@
 // 
***************************************************************************************************************************
 package org.apache.juneau.html;
 
+import static javax.xml.stream.XMLStreamConstants.*;
+import static org.apache.juneau.html.HtmlTag.*;
+
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
@@ -19,6 +22,7 @@ import java.util.*;
 import javax.xml.stream.*;
 
 import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
 import org.apache.juneau.xml.*;
 
 /**
@@ -29,6 +33,11 @@ import org.apache.juneau.xml.*;
 public final class HtmlParserSession extends XmlParserSession {
 
        private XMLEventReader xmlEventReader;
+       private static final Set<String> whitespaceElements = new 
HashSet<String>(
+               Arrays.asList(
+                       new String[]{"br","bs","sp","ff"}
+               )
+       );
 
        /**
         * Create a new session using properties specified in the context.
@@ -56,6 +65,144 @@ public final class HtmlParserSession extends 
XmlParserSession {
                super(ctx, op, input, javaMethod, outer, locale, timeZone);
        }
 
+       /**
+        * Parses CHARACTERS data.
+        * <p>
+        * Precondition:  Pointing to event immediately following opening tag.
+        * Postcondition:  Pointing to closing tag.
+        *
+        * @param r The stream being read from.
+        * @return The parsed string.
+        * @throws XMLStreamException
+        */
+       @Override /* XmlParserSession */
+       public String parseText(XMLStreamReader r) throws XMLStreamException {
+
+               StringBuilder sb = getStringBuilder();
+
+               int et = r.getEventType();
+               if (et == END_ELEMENT)
+                       return "";
+
+               int depth = 0;
+
+               String characters = null;
+
+               while (true) {
+                       if (et == START_ELEMENT) {
+                               if (characters != null) {
+                                       if (sb.length() == 0)
+                                               characters = 
StringUtils.trimStart(characters);
+                                       sb.append(characters);
+                                       characters = null;
+                               }
+                               HtmlTag tag = HtmlTag.forEvent(r);
+                               if (tag == BR) {
+                                       sb.append('\n');
+                                       r.nextTag();
+                               } else if (tag == BS) {
+                                       sb.append('\b');
+                                       r.nextTag();
+                               } else if (tag == SP) {
+                                       et = r.next();
+                                       if (et == CHARACTERS) {
+                                               String s = r.getText();
+                                               if (s.length() > 0) {
+                                                       char c = 
r.getText().charAt(0);
+                                                       if (c == '\u2003')
+                                                               c = '\t';
+                                                       sb.append(c);
+                                               }
+                                               r.nextTag();
+                                       }
+                               } else if (tag == FF) {
+                                       sb.append('\f');
+                                       r.nextTag();
+                               } else if (tag.isOneOf(STRING, NUMBER, 
BOOLEAN)) {
+                                       et = r.next();
+                                       if (et == CHARACTERS) {
+                                               sb.append(r.getText());
+                                               r.nextTag();
+                                       }
+                               } else {
+                                       sb.append('<').append(r.getLocalName());
+                                       for (int i = 0; i < 
r.getAttributeCount(); i++)
+                                               sb.append(' 
').append(r.getAttributeName(i)).append('=').append('\'').append(r.getAttributeValue(i)).append('\'');
+                                       sb.append('>');
+                                       depth++;
+                               }
+                       } else if (et == END_ELEMENT) {
+                               if (characters != null) {
+                                       if (sb.length() == 0)
+                                               characters = 
StringUtils.trimStart(characters);
+                                       if (depth == 0)
+                                               characters = 
StringUtils.trimEnd(characters);
+                                       sb.append(characters);
+                                       characters = null;
+                               }
+                               if (depth == 0)
+                                       break;
+                               
sb.append('<').append(r.getLocalName()).append('>');
+                               depth--;
+                       } else if (et == CHARACTERS) {
+                               characters = r.getText();
+                       }
+                       et = r.next();
+               }
+
+               String s = trim(sb.toString());
+               returnStringBuilder(sb);
+               return s;
+       }
+
+       /**
+        * Identical to {@link #parseText(XMLStreamReader)} except assumes the 
current event
+        *      is the opening tag.
+        * <p>
+        * Precondition:  Pointing to opening tag.
+        * Postcondition:  Pointing to closing tag.
+        *
+        * @param r The stream being read from.
+        * @return The parsed string.
+        * @throws XMLStreamException
+        */
+       @Override /* XmlParserSession */
+       public String getElementText(XMLStreamReader r) throws 
XMLStreamException {
+               r.next();
+               return parseText(r);
+       }
+
+       @Override /* XmlParserSession */
+       public boolean isWhitespaceElement(XMLStreamReader r) {
+               String s = r.getLocalName();
+               return whitespaceElements.contains(s);
+       }
+
+       @Override /* XmlParserSession */
+       public String parseWhitespaceElement(XMLStreamReader r) throws 
XMLStreamException {
+
+               HtmlTag tag = HtmlTag.forEvent(r);
+               int et = r.next();
+               if (tag == BR) {
+                       return "\n";
+               } else if (tag == BS) {
+                       return "\b";
+               } else if (tag == FF) {
+                       return "\f";
+               } else if (tag == SP) {
+                       if (et == CHARACTERS) {
+                               String s = r.getText();
+                               if (s.charAt(0) == '\u2003')
+                                       s = "\t";
+                               r.next();
+                               return decodeString(s);
+                       }
+                       return "";
+               } else {
+                       throw new XMLStreamException("Invalid tag found in 
parseWhitespaceElement(): " + tag);
+               }
+       }
+
        @Override /* ParserSession */
        public boolean close() {
                if (super.close()) {

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
index adcb891..b835030 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlSerializer.java
@@ -237,7 +237,7 @@ public class HtmlSerializer extends XmlSerializer {
                        HtmlClassMeta html = 
sType.getExtendedMeta(HtmlClassMeta.class);
 
                        if (html.isAsXml() || (pMeta != null && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isAsXml())) {
-                               super.serializeAnything(session, out, o, null, 
null, null, false, XmlFormat.MIXED, false, null);
+                               super.serializeAnything(session, out, o, null, 
null, null, false, XmlFormat.MIXED, false, false, null);
 
                        } else if (html.isAsPlainText() || (pMeta != null && 
pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).isAsPlainText())) {
                                out.write(o == null ? "null" : o.toString());
@@ -279,7 +279,7 @@ public class HtmlSerializer extends XmlSerializer {
                                        HtmlLink h = 
o.getClass().getAnnotation(HtmlLink.class);
                                        Object urlProp = 
m.get(h.hrefProperty());
                                        Object nameProp = 
m.get(h.nameProperty());
-                                       out.oTag("a").attrUri("href", 
urlProp).append('>').encodeText(nameProp).eTag("a");
+                                       out.oTag("a").attrUri("href", 
urlProp).append('>').text(nameProp).eTag("a");
                                        cr = CR_SIMPLE;
                                } else {
                                        out.nlIf(! isRoot);
@@ -299,9 +299,9 @@ public class HtmlSerializer extends XmlSerializer {
 
                        } else {
                                if (isRoot)
-                                       
out.sTag("string").encodeText(session.toString(o)).eTag("string");
+                                       
out.sTag("string").text(session.toString(o)).eTag("string");
                                else
-                                       out.encodeText(session.toString(o));
+                                       out.text(session.toString(o));
                                cr = CR_SIMPLE;
                        }
                }
@@ -398,7 +398,7 @@ public class HtmlSerializer extends XmlSerializer {
                                continue;
 
                        out.sTag(i+1, "tr").nl();
-                       out.sTag(i+2, "td").encodeText(key).eTag("td").nl();
+                       out.sTag(i+2, "td").text(key).eTag("td").nl();
                        out.sTag(i+2, "td");
                        try {
                                ContentResult cr = serializeAnything(session, 
out, value, cMeta, key, 2, pMeta, false);

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
new file mode 100644
index 0000000..efa36e2
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlTag.java
@@ -0,0 +1,140 @@
+// 
***************************************************************************************************************************
+// * 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.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.html;
+
+import static javax.xml.stream.XMLStreamConstants.*;
+
+import java.util.*;
+
+import javax.xml.stream.*;
+
+import org.apache.juneau.xml.*;
+
+/**
+ * Predefined tags that occur in the serialized output of the HTML serializer.
+ */
+enum HtmlTag {
+
+       TABLE(1,"<table>"),
+       TR(2,"<tr>"),
+       TH(3,"<th>"),
+       TD(4,"<td>"),
+       UL(5,"<ul>"),
+       LI(6,"<li>"),
+       STRING(7,"<string>"),
+       NUMBER(8,"<number>"),
+       BOOLEAN(9,"<boolean>"),
+       NULL(10,"<null>"),
+       A(11,"<a>"),
+       BR(12,"<br>"),          // newline
+       FF(13,"<ff>"),          // formfeed
+       BS(14,"<bs>"),          // backspace
+       SP(17, "<sp>"),   // space
+       xTABLE(-1,"</table>"),
+       xTR(-2,"</tr>"),
+       xTH(-3,"</th>"),
+       xTD(-4,"</td>"),
+       xUL(-5,"</ul>"),
+       xLI(-6,"</li>"),
+       xSTRING(-7,"</string>"),
+       xNUMBER(-8,"</number>"),
+       xBOOLEAN(-9,"</boolean>"),
+       xNULL(-10,"</null>"),
+       xA(-11,"</a>"),
+       xBR(-12,"</br>"),
+       xFF(-13,"</ff>"),
+       xBS(-14,"</bs>"),
+       xSP(-17, "</sp>");
+
+       private Map<Integer,HtmlTag> cache = new HashMap<Integer,HtmlTag>();
+
+       int id;
+       String label;
+
+       HtmlTag(int id, String label) {
+               this.id = id;
+               this.label = label;
+               cache.put(id, this);
+       }
+
+       static HtmlTag forEvent(XMLStreamReader r) throws XMLStreamException {
+               int et = r.getEventType();
+               if (et == START_ELEMENT)
+                       return forString(r.getLocalName(), false);
+               else if (et == END_ELEMENT)
+                       return forString(r.getLocalName(), true);
+               throw new XMLStreamException("Invalid call to HtmlTag.forEvent 
on event of type ["+XmlUtils.toReadableEvent(r)+"]");
+       }
+
+       static HtmlTag forString(String tag, boolean end) throws 
XMLStreamException {
+               char c = tag.charAt(0);
+               HtmlTag t = null;
+               if (c == 'u')
+                       t = (end ? xUL : UL);
+               else if (c == 'l')
+                       t = (end ? xLI : LI);
+               else if (c == 's') {
+                       c = tag.charAt(1);
+                       if (c == 'p')
+                               t = (end ? xSP : SP);
+                       else if (c == 't')
+                               t = (end ? xSTRING : STRING);
+               }
+               else if (c == 'b') {
+                       c = tag.charAt(1);
+                       if (c == 'o')
+                               t = (end ? xBOOLEAN : BOOLEAN);
+                       else if (c == 'r')
+                               t = (end ? xBR : BR);
+                       else if (c == 's')
+                               t = (end ? xBS : BS);
+               }
+               else if (c == 'a')
+                       t = (end ? xA : A);
+               else if (c == 'n') {
+                       c = tag.charAt(2);
+                       if (c == 'm')
+                               t = (end ? xNUMBER : NUMBER);
+                       else if (c == 'l')
+                               t = (end ? xNULL : NULL);
+               }
+               else if (c == 't') {
+                       c = tag.charAt(1);
+                       if (c == 'a')
+                               t = (end ? xTABLE : TABLE);
+                       else if (c == 'r')
+                               t = (end ? xTR : TR);
+                       else if (c == 'h')
+                               t = (end ? xTH : TH);
+                       else if (c == 'd')
+                               t = (end ? xTD : TD);
+               }
+               else if (c == 'f')
+                       t = (end ? xFF : FF);
+               if (t == null)
+                       throw new XMLStreamException("Unknown tag '"+tag+"' 
encountered");
+               return t;
+       }
+
+       @Override /* Object */
+       public String toString() {
+               return label;
+       }
+
+       public boolean isOneOf(HtmlTag...tags) {
+               for (HtmlTag tag : tags)
+                       if (tag == this)
+                               return true;
+               return false;
+       }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java 
b/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
index 5da552e..3a2a810 100644
--- a/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
+++ b/juneau-core/src/main/java/org/apache/juneau/html/HtmlWriter.java
@@ -14,6 +14,7 @@ package org.apache.juneau.html;
 
 import java.io.*;
 
+import org.apache.juneau.internal.*;
 import org.apache.juneau.xml.*;
 
 /**
@@ -54,9 +55,18 @@ public class HtmlWriter extends XmlWriter {
        
//--------------------------------------------------------------------------------
 
        @Override /* XmlSerializerWriter */
-       public HtmlWriter encodeText(Object o) throws IOException {
+       public HtmlWriter text(Object o, boolean preserveWhitespace) throws 
IOException {
 
+               if (o == null) {
+                       append("<null/>");
+                       return this;
+               }
                String s = o.toString();
+               if (s.isEmpty()) {
+                       append("<sp/>");
+                       return this;
+               }
+
                for (int i = 0; i < s.length(); i++) {
                        char test = s.charAt(i);
                        if (test == '&')
@@ -66,13 +76,21 @@ public class HtmlWriter extends XmlWriter {
                        else if (test == '>')
                                append("&gt;");
                        else if (test == '\n')
-                               append("<br/>");
+                               append(preserveWhitespace ? "\n" : "<br/>");
                        else if (test == '\f')  // XML 1.0 doesn't support 
formfeeds or backslashes, so we have to invent something.
-                               append("<ff/>");
+                               append(preserveWhitespace ? "\f" : "<ff/>");
                        else if (test == '\b')
-                               append("<bs/>");
+                               append(preserveWhitespace ? "\b" : "<bs/>");
                        else if (test == '\t')
-                               append("<tb>&#x2003;</tb>");
+                               append(preserveWhitespace ? "\t" : 
"<sp>&#x2003;</sp>");
+                       else if ((i == 0 || i == s.length()-1) && 
Character.isWhitespace(test)) {
+                               if (preserveWhitespace)
+                                       append(test);
+                               else if (test == ' ')
+                                       append("<sp> </sp>");
+                               else
+                                       
append("<sp>&#x").append(StringUtils.toHex(test)).append(";</sp>");
+                       }
                        else if (Character.isISOControl(test))
                                append("&#" + (int) test + ";");
                        else

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java 
b/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
index 6d3811d..cd2a76b 100644
--- a/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
+++ b/juneau-core/src/main/java/org/apache/juneau/internal/StringUtils.java
@@ -647,6 +647,25 @@ public final class StringUtils {
        }
 
        /**
+        * Converts the specified number into a 4 hexadecimal characters.
+        *
+        * @param num The number to convert to hex.
+        * @return A <code><jk>char</jk>[4]</code> containing the specified 
characters.
+        */
+       public static final char[] toHex(int num) {
+               char[] n = new char[4];
+               int a = num%16;
+               n[3] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
+               int base = 16;
+               for (int i = 1; i < 4; i++) {
+                       a = (num/base)%16;
+                       base <<= 4;
+                       n[3-i] = (char)(a > 9 ? 'A'+a-10 : '0'+a);
+               }
+               return n;
+       }
+
+       /**
         * Tests two strings for equality, but gracefully handles nulls.
         *
         * @param s1 String 1.
@@ -1069,4 +1088,30 @@ public final class StringUtils {
                        sb.append(pattern);
                return sb.toString();
        }
+
+       /**
+        * Trims whitespace characters from the beginning of the specified 
string.
+        *
+        * @param s The string to trim.
+        * @return The trimmed string, or <jk>null</jk> if the string was 
<jk>null</jk>.
+        */
+       public static String trimStart(String s) {
+               if (s != null)
+                       while (s.length() > 0 && 
Character.isWhitespace(s.charAt(0)))
+                               s = s.substring(1);
+               return s;
+       }
+
+       /**
+        * Trims whitespace characters from the end of the specified string.
+        *
+        * @param s The string to trim.
+        * @return The trimmed string, or <jk>null</jk> if the string was 
<jk>null</jk>.
+        */
+       public static String trimEnd(String s) {
+               if (s != null)
+                       while (s.length() > 0 && 
Character.isWhitespace(s.charAt(s.length()-1)))
+                               s = s.substring(0, s.length()-1);
+               return s;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
index 2460e88..115608b 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/serializer/SerializerWriter.java
@@ -39,7 +39,7 @@ public class SerializerWriter extends Writer {
        /** Use-whitespace flag. */
        protected final boolean useWhitespace;
 
-       /** Use-whitespace flag. */
+       /** Trim strings flag. */
        protected final boolean trimStrings;
 
        /** The quote character being used by this writer. */
@@ -186,6 +186,19 @@ public class SerializerWriter extends Writer {
        }
 
        /**
+        * Appends the specified characters to this writer.
+        *
+        * @param characters The characters to append to this writer.
+        * @return This object (for method chaining).
+        * @throws IOException
+        */
+       public SerializerWriter append(char[] characters) throws IOException {
+               for (char c : characters)
+                       append(c);
+               return this;
+       }
+
+       /**
         * Adds a whitespace character to the output if the {@code 
useWhitespace} setting is enabled.
         *
         * @return This object (for method chaining).

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
----------------------------------------------------------------------
diff --git 
a/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java 
b/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
index e51f8f9..26f8357 100644
--- 
a/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
+++ 
b/juneau-core/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
@@ -90,4 +90,15 @@ public abstract class WriterSerializer extends Serializer {
        public final StringObject toStringObject(Object o) {
                return new StringObject(this, o);
        }
+
+       /**
+        * Convenience method for serializing an object and sending it to 
STDOUT.
+        *
+        * @param o The object to serialize.
+        * @return This object (for method chaining).
+        */
+       public final WriterSerializer println(Object o) {
+               System.out.println(toString(o));
+               return this;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/21c0e1ea/juneau-core/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java 
b/juneau-core/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
index 6ffbdf4..4e69c54 100644
--- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
+++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
@@ -41,7 +41,7 @@ public class XmlBeanMeta extends BeanMetaExtended {
                Class<?> c = beanMeta.getClassMeta().getInnerClass();
                Xml xml = c.getAnnotation(Xml.class);
                XmlFormat defaultFormat = null;
-               XmlFormat _contentFormat = null;
+               XmlFormat _contentFormat = DEFAULT;
 
                if (xml != null) {
                        XmlFormat xf = xml.format();
@@ -78,8 +78,8 @@ public class XmlBeanMeta extends BeanMetaExtended {
                                if (! pcm.isMapOrBean())
                                        throw new BeanRuntimeException(c, 
"Invalid type for ATTRS property.  Only properties of type Map and bean can be 
used.");
                                _attrsProperty = p;
-                       } else if (xf.isOneOf(ELEMENTS, MIXED, TEXT, XMLTEXT)) {
-                               if (xf.isOneOf(ELEMENTS, MIXED) && ! 
pcm.isCollectionOrArray())
+                       } else if (xf.isOneOf(ELEMENTS, MIXED, MIXED_PWS, TEXT, 
TEXT_PWS, XMLTEXT)) {
+                               if (xf.isOneOf(ELEMENTS, MIXED, MIXED_PWS) && ! 
pcm.isCollectionOrArray())
                                        throw new BeanRuntimeException(c, 
"Invalid type for {0} property.  Only properties of type Collection and array 
can be used.", xf);
                                if (_contentProperty != null) {
                                        if (xf == _contentFormat)
@@ -217,7 +217,9 @@ public class XmlBeanMeta extends BeanMetaExtended {
         * <ul>
         *      <li>{@link XmlFormat#ELEMENTS}
         *      <li>{@link XmlFormat#MIXED}
+        *      <li>{@link XmlFormat#MIXED_PWS}
         *      <li>{@link XmlFormat#TEXT}
+        *      <li>{@link XmlFormat#TEXT_PWS}
         *      <li>{@link XmlFormat#XMLTEXT}
         *      <li><jk>null</jk>
         *

Reply via email to