KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ibatis > common > xml > NodeletParser


1 package com.ibatis.common.xml;
2
3 import org.w3c.dom.*;
4 import org.xml.sax.*;
5
6 import javax.xml.parsers.DocumentBuilder JavaDoc;
7 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
8 import javax.xml.parsers.FactoryConfigurationError JavaDoc;
9 import javax.xml.parsers.ParserConfigurationException JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.OutputStreamWriter JavaDoc;
12 import java.io.Reader JavaDoc;
13 import java.util.*;
14
15 import com.ibatis.common.exception.NestedRuntimeException;
16
17 /**
18  * The NodeletParser is a callback based parser similar to SAX. The big
19  * difference is that rather than having a single callback for all nodes,
20  * the NodeletParser has a number of callbacks mapped to
21  * various nodes. The callback is called a Nodelet and it is registered
22  * with the NodeletParser against a specific XPath.
23  */

24 public class NodeletParser {
25
26   private Map letMap = new HashMap();
27
28   private boolean validation;
29   private EntityResolver entityResolver;
30
31   /**
32    * Registers a nodelet for the specified XPath. Current XPaths supported
33    * are:
34    * <ul>
35    * <li> Text Path - /rootElement/childElement/text()
36    * <li> Attribute Path - /rootElement/childElement/@theAttribute
37    * <li> Element Path - /rootElement/childElement/theElement
38    * <li> All Elements Named - //theElement
39    * </ul>
40    */

41   public void addNodelet(String JavaDoc xpath, Nodelet nodelet) {
42     letMap.put(xpath, nodelet);
43   }
44
45   /**
46    * Begins parsing from the provided Reader.
47    */

48   public void parse(Reader JavaDoc reader) throws NodeletException {
49     try {
50       Document doc = createDocument(reader);
51       parse(doc.getLastChild());
52     } catch (Exception JavaDoc e) {
53       throw new NodeletException("Error parsing XML. Cause: " + e, e);
54     }
55   }
56
57   /**
58    * Begins parsing from the provided Node.
59    */

60   public void parse(Node node) {
61     Path path = new Path();
62     processNodelet(node, "/");
63     process(node, path);
64   }
65
66   /**
67    * A recursive method that walkes the DOM tree, registers XPaths and
68    * calls Nodelets registered under those XPaths.
69    */

70   private void process(Node node, Path path) {
71     if (node instanceof Element) {
72       // Element
73
String JavaDoc elementName = node.getNodeName();
74       path.add(elementName);
75       processNodelet(node, path.toString());
76       processNodelet(node, new StringBuffer JavaDoc("//").append(elementName).toString());
77
78       // Attribute
79
NamedNodeMap attributes = node.getAttributes();
80       int n = attributes.getLength();
81       for (int i = 0; i < n; i++) {
82         Node att = attributes.item(i);
83         String JavaDoc attrName = att.getNodeName();
84         path.add("@" + attrName);
85         processNodelet(att, path.toString());
86         processNodelet(node, new StringBuffer JavaDoc("//@").append(attrName).toString());
87         path.remove();
88       }
89
90       // Children
91
NodeList children = node.getChildNodes();
92       for (int i = 0; i < children.getLength(); i++) {
93         process(children.item(i), path);
94       }
95       path.add("end()");
96       processNodelet(node, path.toString());
97       path.remove();
98       path.remove();
99     } else if (node instanceof Text) {
100       // Text
101
path.add("text()");
102       processNodelet(node, path.toString());
103       processNodelet(node, "//text()");
104       path.remove();
105     }
106   }
107
108   private void processNodelet(Node node, String JavaDoc pathString) {
109     Nodelet nodelet = (Nodelet) letMap.get(pathString);
110     if (nodelet != null) {
111       try {
112         nodelet.process(node);
113       } catch (Exception JavaDoc e) {
114         throw new NestedRuntimeException("Error parsing XPath '" + pathString + "'. Cause: " + e, e);
115       }
116     }
117   }
118
119   /**
120    * Creates a JAXP Document from a reader.
121    */

122   private Document createDocument(Reader JavaDoc reader) throws ParserConfigurationException JavaDoc, FactoryConfigurationError JavaDoc,
123       SAXException, IOException JavaDoc {
124     DocumentBuilderFactory JavaDoc factory = DocumentBuilderFactory.newInstance();
125     factory.setValidating(validation);
126
127     factory.setNamespaceAware(false);
128     factory.setIgnoringComments(true);
129     factory.setIgnoringElementContentWhitespace(false);
130     factory.setCoalescing(false);
131     factory.setExpandEntityReferences(true);
132
133     OutputStreamWriter JavaDoc errorWriter = new OutputStreamWriter JavaDoc(System.err);
134
135     DocumentBuilder JavaDoc builder = factory.newDocumentBuilder();
136     builder.setEntityResolver(entityResolver);
137     builder.setErrorHandler(new ErrorHandler() {
138       public void error(SAXParseException exception) throws SAXException {
139         throw exception;
140       }
141
142       public void fatalError(SAXParseException exception) throws SAXException {
143         throw exception;
144       }
145
146       public void warning(SAXParseException exception) throws SAXException {
147       }
148     });
149
150     return builder.parse(new InputSource(reader));
151   }
152
153   public void setValidation(boolean validation) {
154     this.validation = validation;
155   }
156
157   public void setEntityResolver(EntityResolver resolver) {
158     this.entityResolver = resolver;
159   }
160
161   /**
162    * Inner helper class that assists with building XPath paths.
163    * <p/>
164    * Note: Currently this is a bit slow and could be optimized.
165    */

166   private static class Path {
167
168     private List nodeList = new ArrayList();
169
170     public Path() {
171     }
172
173     public Path(String JavaDoc path) {
174       StringTokenizer parser = new StringTokenizer(path, "/", false);
175       while (parser.hasMoreTokens()) {
176         nodeList.add(parser.nextToken());
177       }
178     }
179
180     public void add(String JavaDoc node) {
181       nodeList.add(node);
182     }
183
184     public void remove() {
185       nodeList.remove(nodeList.size() - 1);
186     }
187
188     public String JavaDoc toString() {
189       StringBuffer JavaDoc buffer = new StringBuffer JavaDoc("/");
190       for (int i = 0; i < nodeList.size(); i++) {
191         buffer.append(nodeList.get(i));
192         if (i < nodeList.size() - 1) {
193           buffer.append("/");
194         }
195       }
196       return buffer.toString();
197     }
198   }
199
200 }
Popular Tags