KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > extras > DomMapperBase


1 /*
2 Copyright (c) 2004, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.extras;
30
31 import java.io.IOException JavaDoc;
32 import java.util.ArrayList JavaDoc;
33
34 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
35 import javax.xml.parsers.ParserConfigurationException JavaDoc;
36
37 import org.jibx.runtime.JiBXException;
38 import org.jibx.runtime.impl.UnmarshallingContext;
39 import org.w3c.dom.Attr JavaDoc;
40 import org.w3c.dom.Document JavaDoc;
41 import org.w3c.dom.Element JavaDoc;
42 import org.w3c.dom.NamedNodeMap JavaDoc;
43 import org.w3c.dom.Node JavaDoc;
44 import org.w3c.dom.NodeList JavaDoc;
45
46 /**
47  * <p>Base implementation for custom marshaller/unmarshallers to DOM
48  * representation. This provides the basic code used for both single element and
49  * content list handling.</p>
50  *
51  * @author Dennis M. Sosnoski
52  * @version 1.0
53  */

54
55 public class DomMapperBase extends DocumentModelMapperBase
56 {
57     /** Actual document instance (required by DOM). */
58     protected Document JavaDoc m_document;
59     
60     /** Current default namespace URI (<code>null</code> if not determined). */
61     protected String JavaDoc m_defaultNamespaceURI;
62     
63     /** Current default namespace index. */
64     protected int m_defaultNamespaceIndex;
65     
66     /**
67      * Constructor. Initializes the document used by this
68      * marshaller/unmarshaller instance as the owner of all DOM components.
69      *
70      * @throws JiBXException on error creating document
71      */

72     
73     protected DomMapperBase() throws JiBXException {
74         DocumentBuilderFactory JavaDoc dbf = DocumentBuilderFactory.newInstance();
75         dbf.setNamespaceAware(true);
76         try {
77             m_document = dbf.newDocumentBuilder().newDocument();
78         } catch (ParserConfigurationException JavaDoc e) {
79             throw new JiBXException("Unable to create DOM document", e);
80         }
81     }
82     
83     /**
84      * Get index number for declared namespace.
85      *
86      * @param prefix namespace prefix (<code>null</code> if none)
87      * @param uri namespace URI (empty string if none)
88      * @return namespace index number, or <code>-1</code> if not declared or
89      * masked
90      */

91     
92     private int findNamespaceIndex(String JavaDoc prefix, String JavaDoc uri) {
93         if ((prefix == null || "".equals(prefix)) &&
94             (uri == null || "".equals(uri))) {
95             return 0;
96         } else if ("xml".equals(prefix) && XML_NAMESPACE.equals(uri)) {
97             return 1;
98         } else {
99             if (prefix == null) {
100                 if (m_defaultNamespaceURI == null) {
101                     int index = m_xmlWriter.getPrefixIndex("");
102                     if (index >= 0) {
103                         m_defaultNamespaceURI = getNamespaceUri(index);
104                         m_defaultNamespaceIndex = index;
105                         if (m_defaultNamespaceURI.equals(uri)) {
106                             return index;
107                         } else {
108                             return -1;
109                         }
110                     } else {
111                         return -1;
112                     }
113                 } else {
114                     return m_defaultNamespaceURI.equals(uri) ?
115                         m_defaultNamespaceIndex : -1;
116                 }
117             } else {
118                 int index = m_xmlWriter.getPrefixIndex(prefix);
119                 if (index >= 0) {
120                     return getNamespaceUri(index).equals(uri) ?
121                         index : -1;
122                 } else {
123                     return -1;
124                 }
125             }
126         }
127     }
128     
129     /**
130      * Marshal node.
131      *
132      * @param node node to be marshalled
133      * @exception JiBXException on error in marshalling
134      * @exception IOException on error writing to output
135      */

136     
137     protected void marshalNode(Node JavaDoc node) throws JiBXException, IOException JavaDoc {
138         switch (node.getNodeType()) {
139             
140             case Node.CDATA_SECTION_NODE:
141                 m_xmlWriter.writeCData(node.getNodeValue());
142                 break;
143             
144             case Node.COMMENT_NODE:
145                 m_xmlWriter.writeComment(node.getNodeValue());
146                 break;
147             
148             case Node.ELEMENT_NODE:
149                 marshalElement((Element JavaDoc)node);
150                 break;
151             
152             case Node.ENTITY_REFERENCE_NODE:
153                 m_xmlWriter.writeEntityRef(node.getNodeName());
154                 break;
155             
156             case Node.PROCESSING_INSTRUCTION_NODE:
157                 m_xmlWriter.writePI(node.getNodeName(),
158                     node.getNodeValue());
159                 break;
160             
161             case Node.TEXT_NODE:
162                 m_xmlWriter.writeTextContent(node.getNodeValue());
163                 break;
164             
165             default:
166                 break;
167         }
168     }
169     
170     /**
171      * Marshal node list.
172      *
173      * @param content list of nodes to marshal
174      * @exception JiBXException on error in marshalling
175      * @exception IOException on error writing to output
176      */

177     
178     protected void marshalContent(NodeList JavaDoc content)
179         throws JiBXException, IOException JavaDoc {
180         int size = content.getLength();
181         for (int i = 0; i < size; i++) {
182             marshalNode(content.item(i));
183         }
184     }
185     
186     /**
187      * Marshal element with all attributes and content.
188      *
189      * @param element element to be marshalled
190      * @exception JiBXException on error in marshalling
191      * @exception IOException on error writing to output
192      */

193     
194     protected void marshalElement(Element JavaDoc element)
195         throws JiBXException, IOException JavaDoc {
196         
197         // accumulate all needed namespace declarations
198
String JavaDoc prefix = element.getPrefix();
199         String JavaDoc uri = element.getNamespaceURI();
200         int nsi = findNamespaceIndex(prefix, uri);
201         ArrayList JavaDoc nss = null;
202         int defind = -1;
203         String JavaDoc defuri = null;
204         NamedNodeMap JavaDoc attrs = element.getAttributes();
205         int size = attrs.getLength();
206         for (int i = 0; i < size; i++) {
207             Attr JavaDoc attr = (Attr JavaDoc)attrs.item(i);
208             if (XMLNS_NAMESPACE.equals(attr.getNamespaceURI())) {
209                 
210                 // found namespace declaration, convert to simple prefix
211
String JavaDoc declpref = attr.getLocalName();
212                 if ("xmlns".equals(declpref)) {
213                     declpref = null;
214                 }
215                 String JavaDoc decluri = attr.getValue();
216                 if (findNamespaceIndex(declpref, decluri) < 0) {
217                     if (nss == null) {
218                         nss = new ArrayList JavaDoc();
219                     }
220                     nss.add(declpref == null ? "" : declpref);
221                     nss.add(decluri == null ? "" : decluri);
222                     if (declpref == null) {
223                         defind = (nss.size() / 2) - 1;
224                         defuri = decluri;
225                     }
226                     if (uri == decluri) {
227                         nsi = defind;
228                     }
229                 }
230             }
231         }
232         
233         // check for namespace declarations required
234
String JavaDoc[] uris = null;
235         if (nss == null) {
236             m_xmlWriter.startTagOpen(nsi, element.getLocalName());
237         } else {
238             int base = getNextNamespaceIndex();
239             if (defind >= 0) {
240                 m_defaultNamespaceIndex = base + defind;
241                 m_defaultNamespaceURI = defuri;
242             }
243             int length = nss.size() / 2;
244             uris = new String JavaDoc[length];
245             int[] nums = new int[length];
246             String JavaDoc[] prefs = new String JavaDoc[length];
247             for (int i = 0; i < length; i++) {
248                 prefs[i] = (String JavaDoc)nss.get(i*2);
249                 uris[i] = (String JavaDoc)nss.get(i*2+1);
250                 nums[i] = base + i;
251                 if (nsi < 0 && uri.equals(uris[i])) {
252                     if ((prefix == null && prefs[i] == "") ||
253                         (prefix != null && prefix.equals(prefs[i]))) {
254                         nsi = base + i;
255                     }
256                 }
257             }
258             m_xmlWriter.pushExtensionNamespaces(uris);
259             m_xmlWriter.startTagNamespaces(nsi, element.getLocalName(),
260                 nums, prefs);
261             if (defind >= 0) {
262                 m_defaultNamespaceIndex = defind;
263                 m_defaultNamespaceURI = defuri;
264             }
265         }
266         
267         // add attributes if present
268
for (int i = 0; i < size; i++) {
269             Attr JavaDoc attr = (Attr JavaDoc)attrs.item(i);
270             if (!XMLNS_NAMESPACE.equals(attr.getNamespaceURI())) {
271                 int index = 0;
272                 String JavaDoc apref = attr.getPrefix();
273                 if (apref != null) {
274                     index = findNamespaceIndex(apref, attr.getNamespaceURI());
275                 }
276                 m_xmlWriter.addAttribute(index, attr.getLocalName(),
277                      attr.getValue());
278             }
279         }
280         
281         // check for content present
282
NodeList JavaDoc nodes = element.getChildNodes();
283         size = nodes.getLength();
284         if (size > 0) {
285             m_xmlWriter.closeStartTag();
286             marshalContent(element.getChildNodes());
287             m_xmlWriter.endTag(nsi, element.getLocalName());
288         } else {
289             m_xmlWriter.closeEmptyTag();
290         }
291         
292         // pop namespaces if defined by element
293
if (nss != null) {
294             m_xmlWriter.popExtensionNamespaces();
295             if (defind >= 0) {
296                 m_defaultNamespaceURI = null;
297             }
298         }
299     }
300     
301     /**
302      * Unmarshal single node. This unmarshals the next node from the input
303      * stream, up to the close tag of the containing element.
304      *
305      * @return unmarshalled node
306      * @exception JiBXException on error in unmarshalling
307      * @exception IOException on error reading input
308      */

309     
310     protected Node JavaDoc unmarshalNode() throws JiBXException, IOException JavaDoc {
311         while (true) {
312             int cev = m_unmarshalContext.currentEvent();
313             switch (cev) {
314                 
315                 case UnmarshallingContext.CDSECT:
316                     {
317                         String JavaDoc text = m_unmarshalContext.getText();
318                         m_unmarshalContext.nextToken();
319                         return m_document.createCDATASection(text);
320                     }
321                 
322                 case UnmarshallingContext.COMMENT:
323                     {
324                         String JavaDoc text = m_unmarshalContext.getText();
325                         m_unmarshalContext.nextToken();
326                         return m_document.createComment(text);
327                     }
328                 
329                 case UnmarshallingContext.END_TAG:
330                     return null;
331                 
332                 case UnmarshallingContext.ENTITY_REF:
333                     if (m_unmarshalContext.getText() == null) {
334                         String JavaDoc name = m_unmarshalContext.getName();
335                         m_unmarshalContext.nextToken();
336                         return m_document.createEntityReference(name);
337                     } else {
338                         String JavaDoc text = accumulateText();
339                         return m_document.createTextNode(text);
340                     }
341                 
342                 case UnmarshallingContext.PROCESSING_INSTRUCTION:
343                     {
344                         String JavaDoc text = m_unmarshalContext.getText();
345                         m_unmarshalContext.nextToken();
346                         int index = 0;
347                         while (++index < text.length() &&
348                             !isWhitespace(text.charAt(index)));
349                         if (index < text.length()) {
350                             String JavaDoc target = text.substring(0, index);
351                             while (++index < text.length() &&
352                                 isWhitespace(text.charAt(index)));
353                             String JavaDoc data = text.substring(index);
354                             return m_document.
355                                 createProcessingInstruction(target, data);
356                         } else {
357                             return m_document.
358                                 createProcessingInstruction(text, "");
359                         }
360                     }
361                 
362                 case UnmarshallingContext.START_TAG:
363                     return unmarshalElement();
364                 
365                 case UnmarshallingContext.TEXT:
366                     return m_document.createTextNode(accumulateText());
367                     
368                 default:
369                     m_unmarshalContext.nextToken();
370                     
371             }
372         }
373     }
374     
375     /**
376      * Unmarshal node content. This unmarshals everything up to the containing
377      * element close tag, adding each component to the content list supplied. On
378      * return, the parse position will always be at an END_TAG.
379      *
380      * @param parent node to which children are to be added
381      * @exception JiBXException on error in unmarshalling
382      * @exception IOException on error reading input
383      */

384     
385     protected void unmarshalContent(Node JavaDoc parent)
386         throws JiBXException, IOException JavaDoc {
387         Node JavaDoc node;
388         while ((node = unmarshalNode()) != null) {
389             parent.appendChild(node);
390         }
391     }
392     
393     /**
394      * Unmarshal element with all attributes and content. This must be called
395      * with the unmarshalling context positioned at a START_TAG event.
396      *
397      * @return unmarshalled element
398      * @exception JiBXException on error in unmarshalling
399      * @exception IOException on error reading input
400      */

401     
402     protected Element JavaDoc unmarshalElement() throws JiBXException, IOException JavaDoc {
403         
404         // start by creating the actual element
405
String JavaDoc uri = m_unmarshalContext.getNamespace();
406         String JavaDoc prefix = m_unmarshalContext.getPrefix();
407         String JavaDoc name = m_unmarshalContext.getName();
408         if (prefix != null) {
409             name = prefix + ':' + name;
410         }
411         Element JavaDoc element = m_document.createElementNS(uri, name);
412         
413         // add all namespace declarations to element
414
int ncount = m_unmarshalContext.getNamespaceCount();
415         for (int i = 0; i < ncount; i++) {
416             prefix = m_unmarshalContext.getNamespacePrefix(i);
417             uri = m_unmarshalContext.getNamespaceUri(i);
418             if (prefix == null) {
419                 element.setAttributeNS(XMLNS_NAMESPACE, "xmlns", uri);
420             } else {
421                 element.setAttributeNS(XMLNS_NAMESPACE, "xmlns:" + prefix, uri);
422             }
423         }
424         
425         // add all attributes to element
426
int acount = m_unmarshalContext.getAttributeCount();
427         for (int i = 0; i < acount; i++) {
428             prefix = m_unmarshalContext.getAttributePrefix(i);
429             uri = m_unmarshalContext.getAttributeNamespace(i);
430             name = m_unmarshalContext.getAttributeName(i);
431             if (prefix != null) {
432                 name = prefix + ':' + name;
433             }
434             String JavaDoc value = m_unmarshalContext.getAttributeValue(i);
435             element.setAttributeNS(uri, name, value);
436         }
437         
438         // add all content to element
439
int event = m_unmarshalContext.nextToken();
440         if (event != UnmarshallingContext.END_TAG) {
441             unmarshalContent(element);
442         }
443         m_unmarshalContext.nextToken();
444         return element;
445     }
446 }
Popular Tags