1 /*
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided that the
4 * following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright statements and
7 * notices. Redistributions must also contain a copy of this document.
8 *
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 *
13 * 3. The name "Exolab" must not be used to endorse or promote products derived
14 * from this Software without prior written permission of Intalio, Inc. For
15 * written permission, please contact info@exolab.org.
16 *
17 * 4. Products derived from this Software may not be called "Exolab" nor may
18 * "Exolab" appear in their names without prior written permission of Intalio,
19 * Inc. Exolab is a registered trademark of Intalio, Inc.
20 *
21 * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
22 *
23 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY
24 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR
27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * Copyright 2001-2004 (C) Intalio, Inc. All Rights Reserved.
35 *
36 * $Id$ Date Author
37 * Changes 04/06/2001 Arnaud Blandin Created 09/09/2004 Keith Visco Modified for
38 * SAX 2 support
39 */
40 package org.exolab.castor.xml.util;
41
42 import java.util.HashSet;
43 import java.util.Set;
44
45 import org.exolab.castor.types.AnyNode;
46 import org.exolab.castor.xml.Namespaces;
47 import org.exolab.castor.xml.NamespacesStack;
48 import org.xml.sax.ContentHandler;
49 import org.xml.sax.SAXException;
50 import org.xml.sax.helpers.AttributesImpl;
51
52 /**
53 * A class for converting an AnyNode to SAX events.
54 *
55 * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
56 * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
57 *
58 * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
59 */
60 public class AnyNode2SAX2 {
61
62 /** The AnyNode we are firing events for. */
63 private AnyNode _node;
64 /** The Content Handler. */
65 private ContentHandler _handler;
66 /** The stack to store the elements. */
67 private Set<AnyNode> _elements;
68 /** The namespace stack. */
69 private NamespacesStack namespacesStack;
70
71 /**
72 * No-arg constructor.
73 */
74 public AnyNode2SAX2() {
75 this(null, null);
76 }
77
78 /**
79 * Creates a AnyNode2SAX for the given node.
80 * @param node the AnyNode to create AnyNode2SAX2 for.
81 */
82 public AnyNode2SAX2(final AnyNode node) {
83 this(node, null);
84 }
85
86 /**
87 * Creates a AnyNode2SAX2 for the given node and the namespace context.
88 * @param node the AnyNode to create AnyNode2SAX for.
89 * @param namespacesStack a namespace context
90 */
91 public AnyNode2SAX2(final AnyNode node, final NamespacesStack namespacesStack) {
92 _elements = new HashSet<AnyNode>();
93 _node = node;
94 this.namespacesStack = namespacesStack != null ? namespacesStack : new NamespacesStack();
95 }
96
97 /**
98 * Set the ContentHandler to send events to.
99 *
100 * @param handler the document handler to set
101 */
102 public void setContentHandler(final ContentHandler handler) {
103 if (handler == null) {
104 throw new IllegalArgumentException(
105 "AnyNode2SAX2#setContentHandler 'null' value for handler");
106 }
107 _handler = handler;
108 }
109
110 public static void fireEvents(final AnyNode node, final ContentHandler handler)
111 throws SAXException {
112 fireEvents(node, handler, null);
113 }
114
115 public static void fireEvents(final AnyNode node, final ContentHandler handler,
116 final NamespacesStack namespacesStack) throws SAXException {
117 AnyNode2SAX2 eventProducer = new AnyNode2SAX2(node, namespacesStack);
118 eventProducer.setContentHandler(handler);
119
120 // inject a namespace declaration for the AnyNode element
121 if (node != null
122 && namespacesStack != null
123 && node.getNamespacePrefix() != null
124 && namespacesStack.getNamespaceURI(node.getNamespacePrefix()) == null) {
125 handler.startPrefixMapping(node.getNamespacePrefix(), node.getNamespaceURI());
126 }
127
128 eventProducer.start();
129 }
130
131 public void start() throws org.xml.sax.SAXException {
132 if (_node == null || _handler == null) {
133 return;
134 }
135 processAnyNode(_node, _handler);
136 }
137
138 private void processAnyNode(final AnyNode node, final ContentHandler handler)
139 throws SAXException {
140 if (_node == null || _handler == null) {
141 throw new IllegalArgumentException();
142 }
143
144 // -- so we don't potentially get into an endlessloop
145 if (!_elements.add(node)) {
146 return;
147 }
148
149 if (node.getNodeType() == AnyNode.ELEMENT) {
150 // -- node local name
151 String name = node.getLocalName();
152
153 // -- retrieve the namespaces declaration and handle them
154 AnyNode tempNode = node.getFirstNamespace();
155 String prefix = null;
156 while (tempNode != null) {
157 prefix = tempNode.getNamespacePrefix();
158 if (prefix == null) {
159 prefix = "";
160 }
161 String value = tempNode.getNamespaceURI();
162 if (value == null) {
163 value = "";
164 }
165 handler.startPrefixMapping(prefix, value);
166 if (value != null && value.length() > 0) {
167 namespacesStack.addNamespace(prefix, value);
168 }
169 tempNode = tempNode.getNextSibling();
170 }// namespaceNode
171
172 // -- retrieve the attributes and handle them
173 AttributesImpl atts = new AttributesImpl();
174 tempNode = node.getFirstAttribute();
175 String xmlName = null;
176 String value = null;
177 String attUri = null;
178 String attPrefix = null;
179 while (tempNode != null) {
180 xmlName = tempNode.getLocalName();
181 String localName = xmlName;
182 // --retrieve a prefix?
183 attUri = tempNode.getNamespaceURI();
184 if (attUri != null) {
185 attPrefix = namespacesStack.getNamespacePrefix(attUri);
186 } else {
187 attUri = "";
188 }
189
190 if (attPrefix != null && attPrefix.length() > 0) {
191 xmlName = attPrefix + ':' + xmlName;
192 }
193
194 value = tempNode.getStringValue();
195 atts.addAttribute(attUri, localName, xmlName, "CDATA", value);
196 tempNode = tempNode.getNextSibling();
197 }// attributes
198
199 // -- namespace management
200 // _context = _context.createNamespaces();
201 String nsPrefix = node.getNamespacePrefix();
202 String nsURI = node.getNamespaceURI();
203
204 String qName = null;
205 // maybe the namespace is already bound to a prefix in the
206 // namespace context
207 if (nsURI != null && nsURI.length() > 0) {
208 String tempPrefix = namespacesStack.getNamespacePrefix(nsURI);
209 if (tempPrefix != null) {
210 nsPrefix = tempPrefix;
211 } else {
212 namespacesStack.addNamespace(nsPrefix, nsURI);
213 }
214 } else {
215 nsURI = "";
216 }
217
218 if (nsPrefix != null) {
219 int len = nsPrefix.length();
220 if (len > 0) {
221 StringBuffer sb = new StringBuffer(len + name.length() + 1);
222 sb.append(nsPrefix);
223 sb.append(':');
224 sb.append(name);
225 qName = sb.toString();
226 } else {
227 qName = name;
228 }
229 } else {
230 qName = name;
231 }
232
233 try {
234 // _context.declareAsAttributes(atts,true);
235 handler.startElement(nsURI, name, qName, atts);
236 } catch (SAXException sx) {
237 throw new SAXException(sx);
238 }
239
240 // -- handle child&daughter elements
241 tempNode = node.getFirstChild();
242 while (tempNode != null) {
243 namespacesStack.addNewNamespaceScope();
244 processAnyNode(tempNode, handler);
245 tempNode = tempNode.getNextSibling();
246 }
247
248 // -- finish element
249 try {
250 handler.endElement(nsURI, name, qName);
251 namespacesStack.removeNamespaceScope();
252
253 // -- retrieve the namespaces declaration and handle them
254 tempNode = node.getFirstNamespace();
255 while (tempNode != null) {
256 prefix = tempNode.getNamespacePrefix();
257 if (prefix == null) {
258 prefix = "";
259 }
260 handler.endPrefixMapping(prefix);
261 tempNode = tempNode.getNextSibling();
262 } // namespaceNode
263 } catch (org.xml.sax.SAXException sx) {
264 throw new SAXException(sx);
265 }
266 } else {
267 // ELEMENTS
268 if (node.getNodeType() == AnyNode.TEXT) {
269 String value = node.getStringValue();
270 if ((value != null) && (value.length() > 0)) {
271 char[] chars = value.toCharArray();
272 try {
273 handler.characters(chars, 0, chars.length);
274 } catch (org.xml.sax.SAXException sx) {
275 throw new SAXException(sx);
276 }
277 }
278 }
279 }
280 }
281
282 }