View Javadoc
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 }