package org.htmlcleaner;
import org.jdom.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* <p>JDom serializer - creates xml JDom instance out of the TagNode.</p>
*/
public class JDomSerializer {
private DefaultJDOMFactory factory;
protected CleanerProperties props;
protected boolean escapeXml = true;
public JDomSerializer(CleanerProperties props, boolean escapeXml) {
this.props = props;
this.escapeXml = escapeXml;
}
public JDomSerializer(CleanerProperties props) {
this(props, true);
}
public Document createJDom(TagNode rootNode) {
this.factory = new DefaultJDOMFactory();
Element rootElement = createElement(rootNode);
Document document = this.factory.document(rootElement);
setAttributes(rootNode, rootElement);
createSubnodes(rootElement, rootNode.getChildren());
return document;
}
private Element createElement(TagNode node) {
String name = node.getName();
boolean nsAware = props.isNamespacesAware();
String prefix = Utils.getXmlNSPrefix(name);
Map<String, String> nsDeclarations = node.getNamespaceDeclarations();
String nsURI = null;
if (prefix != null) {
name = Utils.getXmlName(name);
if (nsAware) {
if (nsDeclarations != null) {
nsURI = nsDeclarations.get(prefix);
}
if (nsURI == null) {
nsURI = node.getNamespaceURIOnPath(prefix);
}
if (nsURI == null) {
nsURI = prefix;
}
}
} else {
if (nsAware) {
if (nsDeclarations != null) {
nsURI = nsDeclarations.get("");
}
if (nsURI == null) {
nsURI = node.getNamespaceURIOnPath(prefix);
}
}
}
Element element;
if (nsAware && nsURI != null) {
Namespace ns = prefix == null ? Namespace.getNamespace(nsURI) : Namespace.getNamespace(prefix, nsURI);
element = factory.element(name, ns);
} else {
element = factory.element(name);
}
if (nsAware) {
defineNamespaceDeclarations(node, element);
}
return element;
}
private void defineNamespaceDeclarations(TagNode node, Element element) {
Map<String, String> nsDeclarations = node.getNamespaceDeclarations();
if (nsDeclarations != null) {
for (Map.Entry<String, String> nsEntry: nsDeclarations.entrySet()) {
String nsPrefix = nsEntry.getKey();
String nsURI = nsEntry.getValue();
Namespace ns = nsPrefix == null || "".equals(nsPrefix) ? Namespace.getNamespace(nsURI) : Namespace.getNamespace(nsPrefix, nsURI);
element.addNamespaceDeclaration(ns);
}
}
}
private void setAttributes(TagNode node, Element element) {
for (Map.Entry<String, String> entry: node.getAttributes().entrySet()) {
String attrName = entry.getKey();
String attrValue = entry.getValue();
if (escapeXml) {
attrValue = Utils.escapeXml(attrValue, props, true);
}
String attPrefix = Utils.getXmlNSPrefix(attrName);
Namespace ns = null;
if (attPrefix != null) {
attrName = Utils.getXmlName(attrName);
if (props.isNamespacesAware()) {
String nsURI = node.getNamespaceURIOnPath(attPrefix);
if (nsURI == null) {
nsURI = attPrefix;
}
ns = Namespace.getNamespace(attPrefix, nsURI);
}
}
if (ns == null) {
element.setAttribute(attrName, attrValue);
} else {
element.setAttribute(attrName, attrValue, ns);
}
}
}
private void createSubnodes(Element element, List tagChildren) {
if (tagChildren != null) {
Iterator it = tagChildren.iterator();
while (it.hasNext()) {
Object item = it.next();
if (item instanceof CommentNode) {
CommentNode commentNode = (CommentNode) item;
Comment comment = factory.comment( commentNode.getContent().toString() );
element.addContent(comment);
} else if (item instanceof ContentNode) {
String nodeName = element.getName();
String content = item.toString();
boolean specialCase = props.isUseCdataForScriptAndStyle() &&
("script".equalsIgnoreCase(nodeName) || "style".equalsIgnoreCase(nodeName));
if (escapeXml && !specialCase) {
content = Utils.escapeXml(content, props, true);
}
Text text = specialCase ? factory.cdata(content) : factory.text(content);
element.addContent(text);
} else if (item instanceof TagNode) {
TagNode subTagNode = (TagNode) item;
Element subelement = createElement(subTagNode);
setAttributes(subTagNode, subelement);
// recursively create subnodes
createSubnodes(subelement, subTagNode.getChildren());
element.addContent(subelement);
} else if (item instanceof List) {
List sublist = (List) item;
createSubnodes(element, sublist);
}
}
}
}
}