1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.xolite.dom;
17
18
19 import java.util.HashMap;
20 import java.util.Map;
21
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24 import javax.xml.parsers.ParserConfigurationException;
25
26 import net.sf.xolite.XMLSerializable;
27 import net.sf.xolite.XMLSerializeException;
28 import net.sf.xolite.XMLSerializer;
29
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Element;
32 import org.w3c.dom.Node;
33 import org.w3c.dom.Text;
34
35
36
37
38
39 public class DomXMLSerializer implements XMLSerializer {
40
41
42 private static final String NAMESPACE_DEFINITION_URI = "http://www.w3.org/2000/xmlns/";
43
44 private DocumentBuilder builder;
45 private Document currentDocument;
46 private Node currentNode;
47 private Map<String, String> prefixMappings;
48 private Map<Object, Object> customObjects;
49
50
51 public DomXMLSerializer() {
52 try {
53 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
54 factory.setNamespaceAware(true);
55 builder = factory.newDocumentBuilder();
56 } catch (ParserConfigurationException pce) {
57 throw new IllegalStateException("Cannot create DocumentBuilder: " + pce);
58 }
59 prefixMappings = new HashMap<String, String>();
60 }
61
62
63 public DomXMLSerializer(DocumentBuilder docBuilder) {
64 if (docBuilder == null) throw new IllegalArgumentException("docBuilder cannot be null");
65 builder = docBuilder;
66 prefixMappings = new HashMap<String, String>();
67 }
68
69
70 public void clearPrefixMapping() {
71 prefixMappings.clear();
72 }
73
74
75 public Document serializeToDOM(XMLSerializable src) throws XMLSerializeException {
76 startDocument();
77 src.serialize(this);
78 endDocument();
79 return currentDocument;
80 }
81
82
83 public void startDocument() throws XMLSerializeException {
84 Document doc = builder.newDocument();
85 currentDocument = doc;
86 currentNode = doc;
87 }
88
89
90 public void endDocument() throws XMLSerializeException {
91 if (currentNode != currentDocument)
92 throw new XMLSerializeException(
93 "Not all the document nodes are ended (with endElement(..) notification) remaining = " + currentNode);
94 currentNode = null;
95 }
96
97
98 public Document getDocument() {
99 return currentDocument;
100 }
101
102
103 private String getPrefix(String uri, String localName) throws XMLSerializeException {
104 String prefix;
105 if (uri == null) {
106 prefix = null;
107 } else {
108 prefix = prefixMappings.get(uri);
109 if (prefix == null)
110 throw new XMLSerializeException("No prefix defined for URI '" + uri + "' of element <" + localName + ">");
111 }
112 return prefix;
113 }
114
115
116 private void ensurePrefixMappingDefined(String prefix, String uri, Element baseElement) {
117 if ((prefix != null) && (uri != null)) {
118 Element elem = baseElement;
119 String attrName = (prefix.equals("")) ? "xmlns" : "xmlns:" + prefix;
120 String attrVal;
121 Node parent;
122 boolean prefixNotDefined = true;
123 while (prefixNotDefined) {
124 if ((elem != baseElement) && prefix.equals(elem.getPrefix()) && uri.equals(elem.getNamespaceURI())) {
125 prefixNotDefined = false;
126 break;
127 } else {
128
129 attrVal = elem.getAttribute(attrName);
130 if ((attrVal != null) && (attrVal.equals(uri))) {
131 prefixNotDefined = false;
132 break;
133 }
134 }
135 parent = elem.getParentNode();
136 if ((parent != null) && (parent.getNodeType() == Node.ELEMENT_NODE)) elem = (Element) parent;
137 else break;
138 }
139 if (prefixNotDefined) {
140 baseElement.setAttributeNS(NAMESPACE_DEFINITION_URI, attrName, uri);
141 }
142 }
143 }
144
145
146
147
148
149 public void startPrefixMapping(String prefix, String namespaceUri) throws XMLSerializeException {
150 if (!prefixMappings.containsKey(namespaceUri)) prefixMappings.put(namespaceUri, prefix);
151 }
152
153
154 public void startElement(String uri, String localName) throws XMLSerializeException {
155 if ((currentDocument == null) || (currentNode == null)) throw new XMLSerializeException("Document not started");
156 String prefix = getPrefix(uri, localName);
157 String qName = ((prefix == null) || (prefix.equals(""))) ? localName : prefix + ":" + localName;
158 Element el = currentDocument.createElementNS(uri, qName);
159 currentNode.appendChild(el);
160 ensurePrefixMappingDefined(prefix, uri, el);
161 currentNode = el;
162 }
163
164
165 public void attribute(String name, String value) throws XMLSerializeException {
166 attribute(null, name, value);
167 }
168
169
170 public void attribute(String uri, String localName, String value) throws XMLSerializeException {
171 if ((currentDocument == null) || (currentNode == null)) throw new XMLSerializeException("Document not started");
172 if (!(currentNode instanceof Element))
173 throw new XMLSerializeException("You can only add attributes inside an Element");
174 Element current = (Element) currentNode;
175 String prefix = getPrefix(uri, localName);
176 String qName = ((prefix == null) || (prefix.equals(""))) ? localName : prefix + ":" + localName;
177 current.setAttributeNS(uri, qName, value);
178 ensurePrefixMappingDefined(prefix, uri, current);
179 }
180
181
182 public void characters(String text) throws XMLSerializeException {
183 if ((currentDocument == null) || (currentNode == null)) throw new XMLSerializeException("Document not started");
184 if (!(currentNode instanceof Element)) throw new XMLSerializeException("You can only add text inside an Element");
185 Text txt = currentDocument.createTextNode(text);
186 currentNode.appendChild(txt);
187 }
188
189
190 public void charactersMultiLine(String text) throws XMLSerializeException {
191
192 characters(text);
193 }
194
195
196 public void endElement(String uri, String localName) throws XMLSerializeException {
197 if ((currentDocument == null) || (currentNode == null)) throw new XMLSerializeException("Document not started");
198 if ((uri != null) && !uri.equals(currentNode.getNamespaceURI()))
199 throw new XMLSerializeException("Current node namespace URI is not <" + uri + "> but <"
200 + currentNode.getNamespaceURI() + ">");
201 if (!localName.equals(currentNode.getLocalName()))
202 throw new XMLSerializeException("Current node is not <" + localName + "> but <" + currentNode.getNodeName() + ">");
203 Node parent = currentNode.getParentNode();
204 if (parent == null) throw new XMLSerializeException("Error while colsing node");
205 currentNode = parent;
206 }
207
208
209 public void simpleElement(String namespaceUri, String localName, String text) throws XMLSerializeException {
210 startElement(namespaceUri, localName);
211 characters(text);
212 endElement(namespaceUri, localName);
213 }
214
215
216 public Object getCustomObject(Object key) {
217 return (customObjects == null) ? null : customObjects.get(key);
218 }
219
220
221 public void putCustomObject(Object key, Object value) {
222 if (customObjects == null) customObjects = new HashMap<Object, Object>();
223 customObjects.put(key, value);
224 }
225
226
227 }