/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2014 The eXist-db Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package org.exist.util.serializer;
import org.exist.dom.QName;
import org.exist.util.hashtable.ObjectHashSet;
import javax.xml.transform.TransformerException;
import java.io.IOException;
import java.io.Writer;
/**
* HTML5 writer which does not produce well-formed XHTML.
*
* @author Wolfgang
*/
public class HTML5Writer extends XHTML5Writer {
private final static ObjectHashSet<String> EMPTY_TAGS = new ObjectHashSet<String>(31);
static {
EMPTY_TAGS.add("area");
EMPTY_TAGS.add("base");
EMPTY_TAGS.add("br");
EMPTY_TAGS.add("col");
EMPTY_TAGS.add("embed");
EMPTY_TAGS.add("hr");
EMPTY_TAGS.add("img");
EMPTY_TAGS.add("input");
EMPTY_TAGS.add("keygen");
EMPTY_TAGS.add("link");
EMPTY_TAGS.add("meta");
EMPTY_TAGS.add("param");
EMPTY_TAGS.add("source");
EMPTY_TAGS.add("track");
EMPTY_TAGS.add("wbr");
}
private final static ObjectHashSet<String> RAW_TEXT_ELEMENTS = new ObjectHashSet<String>(31);
static {
RAW_TEXT_ELEMENTS.add("script");
RAW_TEXT_ELEMENTS.add("style");
RAW_TEXT_ELEMENTS.add("textarea");
RAW_TEXT_ELEMENTS.add("title");
}
public HTML5Writer() {
super(EMPTY_TAGS, INLINE_TAGS);
}
public HTML5Writer(Writer writer) {
super(writer, EMPTY_TAGS, INLINE_TAGS);
}
@Override
public void endElement(QName qname) throws TransformerException {
if (!isEmptyTag(qname.getLocalPart())) {
super.endElement(qname);
} else {
closeStartTag(true);
endIndent(qname.getNamespaceURI(), qname.getLocalPart());
}
}
@Override
public void endElement(String namespaceURI, String localName, String qname) throws TransformerException {
if (!isEmptyTag(localName)) {
super.endElement(namespaceURI, localName, qname);
} else {
closeStartTag(true);
endIndent(namespaceURI, localName);
}
}
@Override
public void attribute(String qname, String value) throws TransformerException {
try {
if(!tagIsOpen) {
characters(value);
return;
}
final Writer writer = getWriter();
writer.write(' ');
writer.write(qname);
if (!qname.equals(value)) {
writer.write("=\"");
writeChars(value, true);
writer.write('"');
}
} catch(final IOException ioe) {
throw new TransformerException(ioe.getMessage(), ioe);
}
}
@Override
public void attribute(QName qname, String value) throws TransformerException {
try {
if(!tagIsOpen) {
characters(value);
return;
// throw new TransformerException("Found an attribute outside an
// element");
}
final Writer writer = getWriter();
writer.write(' ');
if(qname.getPrefix() != null && qname.getPrefix().length() > 0) {
writer.write(qname.getPrefix());
writer.write(':');
}
if (!qname.getLocalPart().equals(value)) {
writer.write(qname.getLocalPart());
writer.write("=\"");
writeChars(value, true);
writer.write('"');
}
} catch(final IOException ioe) {
throw new TransformerException(ioe.getMessage(), ioe);
}
}
@Override
public void namespace(String prefix, String nsURI) throws TransformerException {
// no namespaces allowed in HTML5
}
@Override
protected void closeStartTag(boolean isEmpty) throws TransformerException {
try {
if (tagIsOpen) {
if (isEmpty) {
if (isEmptyTag(currentTag)) {
getWriter().write(">");
} else {
getWriter().write('>');
getWriter().write("</");
getWriter().write(currentTag);
getWriter().write('>');
}
} else {
getWriter().write('>');
}
tagIsOpen = false;
}
} catch (final IOException ioe) {
throw new TransformerException(ioe.getMessage(), ioe);
}
}
@Override
protected boolean needsEscape(char ch) {
if (RAW_TEXT_ELEMENTS.contains(currentTag)) {
return false;
}
return super.needsEscape(ch);
}
}