Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/aendvari/common/model/xalan/XalanModelTree.java


1   /*
2    * ModelTree.java
3    *
4    * Copyright (c) 2001, 2002 Aendvari, Ltd. All Rights Reserved.
5    *
6    * See the file LICENSE for terms of use.
7    *
8    */
9   
10  package com.aendvari.common.model.xalan;
11  
12  import java.util.*;
13  import java.io.*;
14  
15  import org.w3c.dom.Element;
16  import org.w3c.dom.Node;
17  import org.w3c.dom.NodeList;
18  import org.w3c.dom.NodeList;
19  import org.w3c.dom.Document;
20  import org.w3c.dom.traversal.NodeIterator;
21  
22  import org.w3c.dom.DOMException;
23  
24  import org.xml.sax.SAXException;
25  import org.xml.sax.SAXParseException;
26  
27  import org.apache.xpath.*;
28  import org.apache.xpath.compiler.*;
29  import org.apache.xpath.objects.*;
30  
31  import org.apache.xpath.compiler.Compiler;
32  
33  import org.apache.xml.utils.PrefixResolverDefault;
34  import org.apache.xml.utils.DefaultErrorHandler;
35  
36  import javax.xml.parsers.DocumentBuilderFactory;
37  import javax.xml.parsers.DocumentBuilder;
38  import javax.xml.parsers.ParserConfigurationException;
39  
40  import javax.xml.transform.TransformerException;
41  import javax.xml.transform.ErrorListener;
42  
43  import com.aendvari.common.model.ModelNode;
44  import com.aendvari.common.model.ModelTree;
45  import com.aendvari.common.model.ModelException;
46  import com.aendvari.common.model.ModelParserException;
47  import com.aendvari.common.model.ModelQueryPath;
48  
49  
50  /**
51   * <p>A Xalan XML implementation of the {@link ModelNode} interface.</p>
52   *
53   * @author  Scott Milne
54   *
55   */
56  
57  public class XalanModelTree implements ModelTree
58  {
59    /* Variables */
60  
61    /** The document that represents the model tree */
62    protected Document modelTreeDocument;
63  
64    /** Tracks whether the XML DOM has been modified. */
65    protected boolean modified;
66  
67    /** Runtime context for XPath queries. */
68    protected XPathContext xpathContext;
69  
70    /** XPath expression parser. */
71    protected XPathParser xpathParser;
72  
73    /** XPath query. */
74    protected XPath xpath;
75  
76  
77    /* Constructors. */
78  
79  
80    /**
81     * Constructs a <code>XalanModelTree</code> instance.
82     *
83     */
84  
85    public XalanModelTree()
86      throws ModelException
87    {
88      // create an empty Document
89      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
90  
91      try
92      {
93        DocumentBuilder builder = factory.newDocumentBuilder();
94        modelTreeDocument = builder.newDocument();
95      }
96      catch (ParserConfigurationException pce)
97      {
98        // Parser with specified options can't be built
99        pce.printStackTrace();
100     }
101 
102     // initially, not modified
103     modified = false;
104 
105     // create xpath objects
106     createXPathObjects();
107   }
108 
109   /**
110    * Constructs a <code>XalanModelNode</code> instance wrapping the supplied {@link Document}.
111    *
112    * @param    setModelTree        The XML {@link Document} to wrap.
113    *
114    */
115 
116   public XalanModelTree( Document setModelTree )
117   {
118     modelTreeDocument = setModelTree;
119   }
120 
121   /**
122    * States that the XML DOM has been modified.
123    *
124    */
125 
126   public void setModified()
127   {
128     modified = true;
129   }
130 
131   /**
132    * Creates objects for performing XPath queries.
133    *
134    */
135 
136   protected void createXPathObjects()
137     throws ModelException
138   {
139     // create context
140     xpathContext = new XPathContext();
141 
142     // create default listener
143     ErrorListener errorListener = new DefaultErrorHandler();
144 
145     // create parser
146     xpathParser = new XPathParser(errorListener, null);
147 
148     // create xpath object
149     PrefixResolverDefault prefixResolver = new PrefixResolverDefault(
150       modelTreeDocument.getDocumentElement());
151 
152     try
153     {
154       xpath = new XPath("/", null, prefixResolver, XPath.SELECT, null);
155     }
156     catch (TransformerException exception)
157     {
158       throw new ModelException(exception);
159     }
160   }
161 
162 
163   /* Accessors. */
164 
165 
166   /**
167    * Sets the internal XML {@link Document} object wrapped by this {@link ModelTree}.
168    *
169    * @param    setModelTree        The XML {@link Document} to wrap.
170    *
171    */
172 
173   public void setModelTree( Document setModelTree )
174   {
175     modelTreeDocument = setModelTree;
176   }
177 
178   /**
179    * Returns the internal XML {@link Document} object wrapped by this {@link ModelTree}.
180    *
181    * @return                  The XML {@link Document} wrapped by this {@link ModelTree}.
182    *
183    */
184 
185   public Document getModelTree()
186   {
187     return modelTreeDocument;
188   }
189 
190   /**
191    * Returns the {@link ModelNode} of the DOM model space.
192    *
193    * @return                  A {@link ModelNode} representing the {@link Document}
194    *                      of the DOM.
195    *
196    */
197 
198   public ModelNode getRootNode()
199   {
200     return new XalanModelNode(this, modelTreeDocument);
201   }
202 
203   /**
204    * Creates a {@link ModelNode} object.
205    *
206    * @param    name            The node's name.
207    *
208    * @return                  A new {@link ModelNode} object.
209    *
210    */
211 
212   public ModelNode createNode(String name)
213   {
214     Element node = (Element) modelTreeDocument.createElement(name);
215     return new XalanModelNode(this, node);
216   }
217 
218   /**
219    * Creates a new {@link ModelTree} object.
220    *
221    * @return                  A new {@link ModelTree} object.
222    *
223    */
224 
225   public ModelTree createTree()
226   {
227     return new XalanModelTree();
228   }
229 
230   /**
231    * Creates a {@link ModelNode} object with the supplied value.
232    *
233    * @param    name            The node's name.
234    * @param    value            The node's value.
235    *
236    * @return                  A new {@link ModelNode} object.
237    *
238    */
239 
240   public ModelNode createNode(String name, String value)
241   {
242     ModelNode node = createNode(name);
243     XalanModelNode textNode = new XalanModelNode( this, modelTreeDocument.createTextNode(value) );
244     node.appendChild( textNode );
245     return node;
246   }
247 
248   /**
249    * Returns the {@link ModelNode} using the path provided.
250    *
251    * @param    node            The starting position for the search.
252    * @param    path            The query expression.
253    *
254    * @return                  A {@link ModelNode} using the path provided.
255    *
256    * @exception  ModelException        The search could not be performed.
257    *
258    */
259 
260   public ModelNode getNode( ModelNode node, String path ) throws ModelException
261   {
262     try
263     {
264       Node modelNode = ((XalanModelNode)node).getXmlNode();
265 
266       Node tmpNode = null;
267       XalanModelNode xmlNode = null;
268 
269       // get namespace node
270       Node namespaceNode = modelNode;
271 
272       // resolve from the document's root element
273       if (namespaceNode == modelTreeDocument)
274       {
275         namespaceNode = modelTreeDocument.getDocumentElement();
276       }
277 
278       // create resolver
279       PrefixResolverDefault prefixResolver = new PrefixResolverDefault(namespaceNode);
280 
281       // reset XPathContext if DOM has been modified
282       if (modified)
283       {
284         modified = false;
285         xpathContext.reset();
286       }
287 
288       // compile expression
289       Compiler xpathCompiler = new Compiler();
290       xpathParser.initXPath(xpathCompiler, path, prefixResolver);
291 
292       Expression expression = xpathCompiler.compile(0);
293       xpath.setExpression(expression);
294 
295       // get XObject of XPath expression
296       XObject object = xpath.execute(xpathContext, modelNode, prefixResolver);
297 
298 //      XObject object = XPathAPI.eval(modelNode, path); // TODO: remove
299 
300       // convert XObject to node
301       if (object.getType() == XObject.CLASS_NODESET)
302       {
303         // first node in set is selected node
304         tmpNode = object.nodeset().nextNode();
305 
306         // check for empty node set
307         if (tmpNode == null)
308         {
309           return null;
310         }
311         else
312         {
313           xmlNode = new XalanModelNode(this, tmpNode);
314         }
315       }
316       else
317       if (object.getType() == XObject.CLASS_BOOLEAN)
318       {
319         // get boolean value
320         if (object.bool())
321           xmlNode = new XalanModelNode(this, "true");
322         else
323           xmlNode = new XalanModelNode(this, "false");
324       }
325       else
326       if (object.getType() == XObject.CLASS_NUMBER)
327       {
328         // get number value
329         xmlNode = new XalanModelNode(this, String.valueOf(object.num()));
330       }
331       else
332       if (object.getType() == XObject.CLASS_STRING)
333       {
334         // get string value
335         xmlNode = new XalanModelNode(this, String.valueOf(object.toString()));
336       }
337 
338       return xmlNode;
339     }
340     catch ( TransformerException exception )
341     {
342       throw new ModelException(exception);
343     }
344   }
345 
346   /**
347    * Returns a <code>List</code> of {@link ModelNode}'s using the path provided.
348    *
349    * @param    node            The starting position for the search.
350    * @param    path            The query expression.
351    *
352    * @return                  A <code>List</code> of {@link ModelNode}'s using the path provided.
353    *
354    * @exception  ModelException        The search could not be performed.
355    *
356    */
357 
358   public List getNodes( ModelNode node, String path ) throws ModelException
359   {
360     ArrayList xmlNodeList = new ArrayList();
361 
362     try
363     {
364       Node modelNode = ((XalanModelNode)node).getXmlNode();
365 
366       // get namespace node
367       Node namespaceNode = modelNode;
368 
369       // resolve from the document's root element
370       if (namespaceNode == modelTreeDocument)
371       {
372         namespaceNode = modelTreeDocument.getDocumentElement();
373       }
374 
375       // create resolver
376       PrefixResolverDefault prefixResolver = new PrefixResolverDefault(namespaceNode);
377 
378       // reset XPathContext if DOM has been modified
379       if (modified)
380       {
381         modified = false;
382         xpathContext.reset();
383       }
384 
385       // compile expression
386       Compiler xpathCompiler = new Compiler();
387       xpathParser.initXPath(xpathCompiler, path, prefixResolver);
388 
389       Expression expression = xpathCompiler.compile(0);
390       xpath.setExpression(expression);
391 
392       // get XObject of XPath expression
393       XObject object = xpath.execute(xpathContext, modelNode, prefixResolver);
394 
395 //      NodeList nodeList = XPathAPI.selectNodeList( modelNode, path );
396 
397       // convert XObject to node list
398       if (object.getType() == XObject.CLASS_NODESET)
399       {
400         NodeIterator nodeIterator = object.nodeset();
401 
402         if (nodeIterator != null)
403         {
404           while (true)
405           {
406             Node tmpNode = nodeIterator.nextNode();
407             if (tmpNode == null) break;
408 
409             xmlNodeList.add( new XalanModelNode(this, tmpNode) );
410           }
411         }
412       }
413       else
414       if (object.getType() == XObject.CLASS_BOOLEAN)
415       {
416         // get boolean value
417         if (object.bool())
418           xmlNodeList.add(new XalanModelNode(this, "true"));
419         else
420           xmlNodeList.add(new XalanModelNode(this, "false"));
421       }
422       else
423       if (object.getType() == XObject.CLASS_NUMBER)
424       {
425         // get number value
426         xmlNodeList.add(new XalanModelNode(this, String.valueOf(object.num())));
427       }
428       else
429       if (object.getType() == XObject.CLASS_STRING)
430       {
431         // get string value
432         xmlNodeList.add(new XalanModelNode(this, String.valueOf(object.toString())));
433       }
434     }
435     catch ( TransformerException exception )
436     {
437       throw new ModelException(exception);
438     }
439 
440     return xmlNodeList;
441   }
442 
443   /**
444    * Replaces the current {@link ModelTree} with the given XML.
445    *
446    * @param    xmlFile            A path to the XML file.
447    *
448    * @exception  ModelParserException    The file could not be parsed.
449    *
450    */
451 
452   public void loadFromFile( String xmlFile ) throws ModelParserException
453   {
454     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
455 
456     try
457     {
458       DocumentBuilder builder = factory.newDocumentBuilder();
459       modelTreeDocument = builder.parse( new File(xmlFile) );
460     }
461     catch (Exception exception)
462     {
463       throw new ModelParserException(exception);
464     }
465   }
466 
467   /**
468    * Replaces the current {@link ModelTree} with the given XML stream.
469    *
470    * @param    xmlStream          An {@link java.io.InputStream} instance.
471    *
472    * @exception  ModelParserException    The stream could not be parsed.
473    *
474    */
475 
476   public void loadFromStream( InputStream xmlStream ) throws ModelParserException
477   {
478     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
479 
480     try
481     {
482       DocumentBuilder builder = factory.newDocumentBuilder();
483       modelTreeDocument = builder.parse( xmlStream );
484     }
485     catch (Exception exception)
486     {
487       throw new ModelException(exception);
488     }
489   }
490 }
491