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