1 /* GnomeDocument.java -
2    Copyright (C) 2004 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.xml.libxmlj.dom;
39 
40 import gnu.java.lang.CPStringBuilder;
41 import gnu.xml.dom.DomNodeIterator;
42 
43 import java.util.Iterator;
44 
45 import org.w3c.dom.Attr;
46 import org.w3c.dom.CDATASection;
47 import org.w3c.dom.Comment;
48 import org.w3c.dom.Document;
49 import org.w3c.dom.DocumentFragment;
50 import org.w3c.dom.DocumentType;
51 import org.w3c.dom.DOMConfiguration;
52 import org.w3c.dom.DOMErrorHandler;
53 import org.w3c.dom.DOMException;
54 import org.w3c.dom.DOMImplementation;
55 import org.w3c.dom.DOMStringList;
56 import org.w3c.dom.Element;
57 import org.w3c.dom.EntityReference;
58 import org.w3c.dom.Node;
59 import org.w3c.dom.NodeList;
60 import org.w3c.dom.ProcessingInstruction;
61 import org.w3c.dom.Text;
62 import org.w3c.dom.UserDataHandler;
63 import org.w3c.dom.traversal.DocumentTraversal;
64 import org.w3c.dom.traversal.NodeFilter;
65 import org.w3c.dom.traversal.NodeIterator;
66 import org.w3c.dom.traversal.TreeWalker;
67 import org.w3c.dom.xpath.XPathEvaluator;
68 import org.w3c.dom.xpath.XPathException;
69 import org.w3c.dom.xpath.XPathExpression;
70 import org.w3c.dom.xpath.XPathNSResolver;
71 
72 /**
73  * A DOM document node implemented in libxml2.
74  *
75  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
76  */
77 public class GnomeDocument
78   extends GnomeNode
79   implements Document, DOMConfiguration, XPathEvaluator, DocumentTraversal
80 {
81 
82   DOMImplementation dom;
83 
84   /**
85    * Not currently used.
86    */
87   boolean strictErrorChecking;
88 
89   /* DOMConfiguration */
90   boolean canonicalForm = false;
91   boolean cdataSections = true;
92   boolean checkCharacterNormalization = false;
93   boolean comments = true;
94   boolean datatypeNormalization = false;
95   boolean elementContentWhitespace = true;
96   boolean entities = true;
97   DOMErrorHandler errorHandler;
98   boolean namespaces = true;
99   boolean namespaceDeclarations = true;
100   boolean normalizeCharacters = false;
101   boolean splitCdataSections = true;
102   boolean validate = false;
103   boolean validateIfSchema = false;
104   boolean wellFormed = true;
105 
GnomeDocument(Object id)106   GnomeDocument(Object id)
107   {
108     super(id);
109     strictErrorChecking = true;
110   }
111 
finalize()112   protected void finalize()
113   {
114     free(id);
115   }
116 
free(Object id)117   private native void free(Object id);
118 
getDoctype()119   public native DocumentType getDoctype();
120 
getImplementation()121   public DOMImplementation getImplementation()
122   {
123     return dom;
124   }
125 
getDocumentElement()126   public native Element getDocumentElement();
127 
createElement(String tagName)128   public Element createElement(String tagName)
129     throws DOMException
130   {
131     return createElementNS(null, tagName);
132   }
133 
createDocumentType(String name, String publicId, String systemId)134   public native DocumentType createDocumentType(String name, String publicId,
135                                                 String systemId);
136 
createDocumentFragment()137   public native DocumentFragment createDocumentFragment();
138 
createTextNode(String data)139   public native Text createTextNode(String data);
140 
createComment(String data)141   public native Comment createComment(String data);
142 
createCDATASection(String data)143   public native CDATASection createCDATASection(String data)
144     throws DOMException;
145 
createProcessingInstruction(String target, String data)146   public native ProcessingInstruction createProcessingInstruction(String target,
147                                                                   String data)
148     throws DOMException;
149 
createAttribute(String name)150   public Attr createAttribute(String name)
151     throws DOMException
152   {
153     return createAttributeNS(null, name);
154   }
155 
createEntityReference(String name)156   public native EntityReference createEntityReference(String name)
157     throws DOMException;
158 
getElementsByTagName(String tagName)159   public native NodeList getElementsByTagName(String tagName);
160 
importNode(Node importedNode, boolean deep)161   public Node importNode(Node importedNode, boolean deep)
162     throws DOMException
163   {
164     Node ret = xmljImportNode(importedNode, deep);
165     if (importedNode instanceof GnomeNode)
166       {
167         ((GnomeNode) importedNode)
168           .notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED,
169                                   importedNode, ret);
170       }
171     return ret;
172   }
173 
xmljImportNode(Node importedNode, boolean deep)174   private native Node xmljImportNode(Node importedNode, boolean deep)
175     throws DOMException;
176 
createElementNS(String namespaceURI, String qualifiedName)177   public native Element createElementNS(String namespaceURI, String
178                                         qualifiedName)
179     throws DOMException;
180 
createAttributeNS(String namespaceURI, String qualifiedName)181   public native Attr createAttributeNS(String namespaceURI, String
182                                        qualifiedName)
183     throws DOMException;
184 
getElementsByTagNameNS(String namespaceURI, String localName)185   public native NodeList getElementsByTagNameNS(String namespaceURI,
186       String localName);
187 
getElementById(String elementId)188   public Element getElementById(String elementId)
189   {
190     Element element = xmljGetElementById(elementId);
191     if (element == null)
192       {
193         TreeWalker walker = createTreeWalker(this, NodeFilter.SHOW_ELEMENT,
194                                              null, false);
195         for (Node node = walker.nextNode(); node != null;
196              node = walker.nextNode())
197           {
198             GnomeElement e = (GnomeElement) node;
199             if (e.userIdAttrs != null)
200               {
201                 for (Iterator i = e.userIdAttrs.iterator(); i.hasNext(); )
202                   {
203                     Attr attr = (Attr) i.next();
204                     if (attr.getNodeValue().equals(elementId))
205                       {
206                         return e;
207                       }
208                   }
209               }
210           }
211       }
212     return element;
213   }
214 
xmljGetElementById(String elementId)215   private native Element xmljGetElementById(String elementId);
216 
217   // DOM Level 3 methods
218 
getInputEncoding()219   public native String getInputEncoding();
220 
getXmlEncoding()221   public native String getXmlEncoding();
222 
getXmlStandalone()223   public native boolean getXmlStandalone();
224 
setXmlStandalone(boolean xmlStandalone)225   public native void setXmlStandalone(boolean xmlStandalone);
226 
getXmlVersion()227   public native String getXmlVersion();
228 
setXmlVersion(String xmlVersion)229   public native void setXmlVersion(String xmlVersion);
230 
getStrictErrorChecking()231   public boolean getStrictErrorChecking()
232   {
233     return strictErrorChecking;
234   }
235 
setStrictErrorChecking(boolean strictErrorChecking)236   public void setStrictErrorChecking(boolean strictErrorChecking)
237   {
238     this.strictErrorChecking = strictErrorChecking;
239   }
240 
getDocumentURI()241   public native String getDocumentURI();
242 
setDocumentURI(String documentURI)243   public native void setDocumentURI(String documentURI);
244 
adoptNode(Node source)245   public Node adoptNode(Node source)
246     throws DOMException
247   {
248     if (source == null || !(source instanceof GnomeNode))
249       {
250         return null;
251       }
252     Node ret = xmljAdoptNode(source);
253     if (source instanceof GnomeNode)
254       {
255         ((GnomeNode) source).
256           notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED,
257                                  source, ret);
258       }
259     return ret;
260   }
261 
xmljAdoptNode(Node source)262   private native Node xmljAdoptNode(Node source)
263     throws DOMException;
264 
getDomConfig()265   public DOMConfiguration getDomConfig()
266   {
267     return this;
268   }
269 
normalizeDocument()270   public void normalizeDocument()
271   {
272     normalize();
273   }
274 
renameNode(Node n, String namespaceURI, String qualifiedName)275   public native Node renameNode(Node n, String namespaceURI,
276                                 String qualifiedName);
277 
278   // -- DOMConfiguration methods --
279 
setParameter(String name, Object value)280   public void setParameter(String name, Object value)
281     throws DOMException
282   {
283     name = name.toLowerCase();
284     if ("canonical-form".equals(name))
285       {
286         /* optional
287         canonicalForm = getBooleanValue(value);*/
288       }
289     else if ("cdata-sections".equals(name))
290       {
291         cdataSections = getBooleanValue(value);
292       }
293     else if ("check-character-normalization".equals(name))
294       {
295         /* optional
296         checkCharacterNormalization = getBooleanValue(value);*/
297       }
298     else if ("comments".equals(name))
299       {
300         comments = getBooleanValue(value);
301       }
302     else if ("datatype-normalization".equals(name))
303       {
304         /* optional
305         datatypeNormalization = getBooleanValue(value);*/
306       }
307     else if ("element-content-whitespace".equals(name))
308       {
309         /* optional
310         elementContentWhitespace = getBooleanValue(value);*/
311       }
312     else if ("entities".equals(name))
313       {
314         entities = getBooleanValue(value);
315       }
316     else if ("error-handler".equals(name))
317       {
318         errorHandler = (DOMErrorHandler) value;
319       }
320     else if ("infoset".equals(name))
321       {
322         if (getBooleanValue(value))
323           {
324             validateIfSchema = false;
325             entities = false;
326             datatypeNormalization = false;
327             cdataSections = false;
328             namespaceDeclarations = true;
329             wellFormed = true;
330             elementContentWhitespace = true;
331             comments = true;
332             namespaces = true;
333           }
334       }
335     else if ("namespaces".equals(name))
336       {
337         /* optional
338         namespaces = getBooleanValue(value);*/
339       }
340     else if ("namespace-declarations".equals(name))
341       {
342         namespaceDeclarations = getBooleanValue(value);
343       }
344     else if ("normalize-characters".equals(name))
345       {
346         /* optional
347         normalizeCharacters = getBooleanValue(value);*/
348       }
349     else if ("split-cdata-sections".equals(name))
350       {
351         splitCdataSections = getBooleanValue(value);
352       }
353     else if ("validate".equals(name))
354       {
355         /* optional
356         validate = getBooleanValue(value);*/
357       }
358     else if ("validate-if-schema".equals(name))
359       {
360         /* optional
361         validateIfSchema = getBooleanValue(value);*/
362       }
363     else if ("well-formed".equals(name))
364       {
365         /* optional
366         wellFormed = getBooleanValue(value);*/
367       }
368     else
369       {
370         throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name);
371       }
372   }
373 
getParameter(String name)374   public Object getParameter(String name)
375     throws DOMException
376   {
377     name = name.toLowerCase();
378     if ("canonical-form".equals(name))
379       {
380         return Boolean.valueOf(canonicalForm);
381       }
382     else if ("cdata-sections".equals(name))
383       {
384         return Boolean.valueOf(cdataSections);
385       }
386     else if ("check-character-normalization".equals(name))
387       {
388         return Boolean.valueOf(checkCharacterNormalization);
389       }
390     else if ("comments".equals(name))
391       {
392         return Boolean.valueOf(comments);
393       }
394     else if ("datatype-normalization".equals(name))
395       {
396         return Boolean.valueOf(datatypeNormalization);
397       }
398     else if ("element-content-whitespace".equals(name))
399       {
400         return Boolean.valueOf(elementContentWhitespace);
401       }
402     else if ("entities".equals(name))
403       {
404         return Boolean.valueOf(entities);
405       }
406     else if ("error-handler".equals(name))
407       {
408         return errorHandler;
409       }
410     else if ("infoset".equals(name))
411       {
412         return Boolean.valueOf(!validateIfSchema &&
413                                !entities &&
414                                !datatypeNormalization &&
415                                !cdataSections &&
416                                namespaceDeclarations &&
417                                wellFormed &&
418                                elementContentWhitespace &&
419                                comments &&
420                                namespaces);
421       }
422     else if ("namespaces".equals(name))
423       {
424         return Boolean.valueOf(namespaces);
425       }
426     else if ("namespace-declarations".equals(name))
427       {
428         return Boolean.valueOf(namespaceDeclarations);
429       }
430     else if ("normalize-characters".equals(name))
431       {
432         return Boolean.valueOf(normalizeCharacters);
433       }
434     else if ("split-cdata-sections".equals(name))
435       {
436         return Boolean.valueOf(splitCdataSections);
437       }
438     else if ("validate".equals(name))
439       {
440         return Boolean.valueOf(validate);
441       }
442     else if ("validate-if-schema".equals(name))
443       {
444         return Boolean.valueOf(validateIfSchema);
445       }
446     else if ("well-formed".equals(name))
447       {
448         return Boolean.valueOf(wellFormed);
449       }
450     else
451       {
452         throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name);
453       }
454   }
455 
canSetParameter(String name, Object value)456   public boolean canSetParameter(String name, Object value)
457   {
458     name = name.toLowerCase();
459     if ("error-handler".equals(name))
460       {
461         return (value == null || value instanceof DOMErrorHandler);
462       }
463     return ("cdata-sections".equals(name) ||
464             "comments".equals(name) ||
465             "entities".equals(name) ||
466             "namespace-declarations".equals(name) ||
467             "split-cdata-sections".equals(name));
468   }
469 
getParameterNames()470   public DOMStringList getParameterNames()
471   {
472     String[] names = new String[] {
473       "canonical-form",
474       "cdata-sections",
475       "check-character-normalization",
476       "comments",
477       "datatype-normalization",
478       "element-content-whitespace",
479       "entities",
480       "error-handler",
481       "infoset",
482       "namespaces",
483       "namespace-declarations",
484       "normalize-characters",
485       "split-cdata-sections",
486       "validate",
487       "validate-if-schema",
488       "well-formed"
489     };
490     return new GnomeDOMStringList(names);
491   }
492 
getBooleanValue(Object value)493   private boolean getBooleanValue(Object value)
494   {
495     if (value instanceof Boolean)
496       {
497         return ((Boolean) value).booleanValue();
498       }
499     else if (value instanceof String)
500       {
501         return Boolean.valueOf ((String) value).booleanValue();
502       }
503     return false;
504   }
505 
506   // -- XPathEvaluator methods --
507 
createExpression(String expression, XPathNSResolver resolver)508   public XPathExpression createExpression(String expression,
509                                           XPathNSResolver resolver)
510     throws XPathException, DOMException
511   {
512     return new GnomeXPathExpression(this, expression, resolver);
513   }
514 
createNSResolver(Node nodeResolver)515   public XPathNSResolver createNSResolver(Node nodeResolver)
516   {
517     return new GnomeXPathNSResolver(nodeResolver);
518   }
519 
evaluate(String expression, Node contextNode, XPathNSResolver resolver, short type, Object result)520   public native Object evaluate(String expression,
521                                 Node contextNode,
522                                 XPathNSResolver resolver,
523                                 short type,
524                                 Object result)
525     throws XPathException, DOMException;
526 
527   // -- DocumentTraversal methods --
528 
createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion)529   public NodeIterator createNodeIterator(Node root,
530                                          int whatToShow,
531                                          NodeFilter filter,
532                                          boolean entityReferenceExpansion)
533     throws DOMException
534   {
535     return new DomNodeIterator(root, whatToShow, filter,
536                                entityReferenceExpansion, false);
537   }
538 
createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion)539   public TreeWalker createTreeWalker(Node root,
540                                     int whatToShow,
541                                     NodeFilter filter,
542                                     boolean entityReferenceExpansion)
543     throws DOMException
544   {
545     return new DomNodeIterator(root, whatToShow, filter,
546                                entityReferenceExpansion, true);
547   }
548 
549   // -- Debugging --
550 
toString()551   public String toString()
552   {
553     CPStringBuilder buffer = new CPStringBuilder(getClass().getName());
554     buffer.append("[version=");
555     buffer.append(getXmlVersion());
556     buffer.append(",standalone=");
557     buffer.append(getXmlStandalone());
558     buffer.append("]");
559     return buffer.toString();
560   }
561 
562 }
563