KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > util > TagTracker


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.util;
24
25 import java.util.Hashtable JavaDoc;
26 import java.util.Stack JavaDoc;
27
28 import org.xquark.schema.validation.ElementPSVInfoset;
29 import org.xquark.schema.validation.PSVInfoset;
30
31 /**
32  * This class belongs to a library that allow to hide SAX specificities when
33  * constructing java objects from an XML document with an XML schema.
34  * This class is the base node used in a stack to keep track of the current tag.
35  * This class must be extended in order to perform specific action for a tag.
36  *
37  * @see org.xquark.xml.util.SaxMapper
38  */

39 public class TagTracker
40 {
41     private static final String JavaDoc RCSRevision = "$Revision: 1.2 $";
42     private static final String JavaDoc RCSName = "$Name: $";
43
44     // Table of tag trackers.
45
// This table contains an entry for
46
// every tag name that this TagTracker
47
// has been configured to follow.
48
// This is a single-level parent-child relation.
49
//
50
private Hashtable JavaDoc trackers = new Hashtable JavaDoc();
51
52     // Useful for skipping tag names that are not
53
// being tracked.
54
private static SkippingTagTracker skip = new SkippingTagTracker();
55
56     // default constructor
57
public TagTracker()
58     {}
59
60     /**
61      * Configuration method for setting up a network of tag trackers...
62      * Each parent tag name should be configured (call this method) for each
63      * child tag name that it will track.
64      * @param tagName an absolute or relative path using the canonical XPath
65      * syntax (/{nsuri1}n1/{nsuri2}n2)
66      * @param tracker child
67      */

68     public void track(String JavaDoc tagName, TagTracker tracker)
69     {
70         trackAny(tagName, tracker);
71     }
72     /**
73      * Configuration method for setting up a network of tag trackers...
74      * Each parent tag name should be configured (call this method) for each
75      * child tag name that it will track.
76      * @param attName an absolute or relative path using the canonical XPath
77      * syntax (/{nsuri1}n1/@{nsuri2}n2)
78      * @param attHandler attribute actual value handler
79      */

80     public void trackAttribute(String JavaDoc attName, AttributeTracker attHandler)
81     {
82         trackAny(attName, attHandler);
83     }
84
85     private void trackAny(String JavaDoc tagName, Object JavaDoc o)
86     {
87
88         int slashOffset = tagName.indexOf("/");
89
90         if (slashOffset < 0)
91         {
92             // if it is a simple tag name ( no "/" seperators )
93
// simply add it.
94
trackers.put(tagName, o);
95
96         }
97         else if (slashOffset == 0)
98         {
99             // Oooops leading slash, remove it and
100
// try again recursivley.
101
trackAny(tagName.substring(1), o);
102
103         }
104         else
105         {
106             // if it is not a simple tag name
107
// recursively add the tag.
108
String JavaDoc topTagName = tagName.substring(0, slashOffset);
109             String JavaDoc remainderOfTagName = tagName.substring(slashOffset + 1);
110             TagTracker child = (TagTracker) trackers.get(topTagName);
111             if (child == null)
112             {
113                 // Not currently tracking this
114
// tag. Add new tracker.
115
child = new TagTracker();
116                 trackers.put(topTagName, child);
117             }
118             child.trackAny(remainderOfTagName, o);
119
120         }
121
122     }
123
124     // Tag trackers work together on a stack.
125
// The tag tracker at the top of the stack
126
// is the "active" tag tracker and is responsible
127
// for delegating the tracking to a child tag
128
// tracker or putting a skipping place marker on the
129
// stack.
130
//
131
public void startElement(ElementPSVInfoset infoSet, Stack JavaDoc tagStack)
132     {
133         // Lookup up the tag name in the tracker table.
134
// Note, this implementation does not address
135
// using XML name space support that is now available
136
// with SAX2.
137
// We are simply using the localName as a key
138
// to find a possible tracker.
139
TagTracker tracker = (TagTracker) trackers.get(
140         getExpandedName(infoSet.getNamespaceURI(), infoSet.getLocalName(), false));
141
142         //
143
// Are we tracking this tag name?
144
//
145
if (tracker == null)
146         {
147             // Not tracking this
148
// tag name. Skip the
149
// entire branch.
150
tagStack.push(skip);
151         }
152         else
153         {
154
155             // Found a tracker for this
156
// tag name. Make it the
157
// new top of stack tag
158
// tracker
159

160             // Send the deactivate event to this tracker.
161
onDeactivate();
162
163             // Send the on start to the new active
164
// tracker.
165
tracker.onStart(infoSet.getNamespaceURI(),
166                             infoSet.getLocalName());
167                 
168             // Fire events to registered attribute trackers
169
int nbAtts = infoSet.getAttributeCount();
170             AttributeTracker attHandler;
171             PSVInfoset attInfoset;
172             
173             for (int i = 0; i < nbAtts; i++)
174             {
175                 attInfoset = infoSet.getAttributePSVInfoset(i);
176                 attHandler =
177                     (AttributeTracker) tracker.trackers.get(
178                         getExpandedName(
179                             attInfoset.getNamespaceURI(),
180                             attInfoset.getLocalName(),
181                             true));
182                 if (attHandler != null)
183                     attHandler.onAttributeEncountered(
184                         attInfoset.getNamespaceURI(),
185                         attInfoset.getLocalName(),
186                         attInfoset.getActualValue(),
187                         attInfoset.getSpecified() == PSVInfoset.SCHEMA ? true : false);
188             }
189             
190             tagStack.push(tracker);
191
192         }
193
194     }
195
196     // Tag trackers work together on a stack.
197
// The tag tracker at the top of the stack
198
// is the "active" tag tracker and is responsible
199
// for reestablishing it's parent tag tracker
200
// ( next to top of stack ) when it has
201
// been notified of the closing tag.
202
//
203
public void endElement(
204         ElementPSVInfoset infoSet,
205         Stack JavaDoc tagStack)
206     {
207
208         // Send the end event.
209
onEnd(infoSet.getNamespaceURI(),
210                 infoSet.getLocalName(),
211                 infoSet.getActualValue());
212
213         // Clean up the stack...
214
tagStack.pop();
215
216         // Send the reactivate event.
217
TagTracker activeTracker = (TagTracker) tagStack.peek();
218         if (activeTracker != null)
219         {
220             activeTracker.onReactivate();
221         }
222
223     }
224
225     // Methods for collecting content. These methods
226
// are intended to be overridden with specific
227
// actions for nodes in the tag tracking network
228
// that require
229

230     public void onStart(
231         String JavaDoc namespaceURI,
232         String JavaDoc localName)
233     {
234
235         // default is no action...
236
}
237
238     public void onDeactivate()
239     {
240
241         // default is no action...
242
}
243
244     public void onEnd(
245         String JavaDoc namespaceURI,
246         String JavaDoc localName,
247         Object JavaDoc actualValue)
248     {
249
250         // default is no action...
251
}
252
253     public void onReactivate()
254     {
255
256         // default is no action...
257
}
258
259
260     private String JavaDoc getExpandedName(
261         String JavaDoc namespace,
262         String JavaDoc localName,
263         boolean att)
264     {
265         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
266
267         if (att)
268             sb.append('@');
269         if (namespace != null && !namespace.equals(""))
270         {
271             sb.append('{');
272             sb.append(namespace);
273             sb.append('}');
274         }
275         sb.append(localName);
276         return sb.toString();
277     }
278
279 }
280 class SkippingTagTracker extends TagTracker
281 {
282     private static final String JavaDoc RCSRevision = "$Revision: 1.2 $";
283     private static final String JavaDoc RCSName = "$Name: $";
284
285     // Tag trackers work together on a stack.
286
// The tag tracker at the top of the stack
287
// is the "active" tag tracker.
288
//
289
// This class represents a skipping place
290
// marker on the stack. When a real tag
291
// tracker places a skipping tag tracker on
292
// the stack, that is an indication that
293
// all tag names found during the skip are
294
// of no intrest to the tag tracking network.
295
//
296
// This means that if the skipping tag tracker
297
// is notified of a new tag name, this new
298
// tag name should also be skipped.
299
//
300
// Since this class never varies it's behavior,
301
// it is ok for it to skip new tag names by
302
// placing itself on the stack again.
303
public void startElement(ElementPSVInfoset infoSet, Stack JavaDoc tagStack)
304     {
305
306         //
307
// If the current tag name is being
308
// skipped, all children should be
309
// skipped.
310
//
311
tagStack.push(this);
312
313     }
314
315     //
316
// The skipping tag tracker has
317
// nothing special to do when
318
// a closing tag is found other
319
// than to remove itself from
320
// the stack, which as a side
321
// effect replaces it with it's
322
// parent as the "active", top
323
// of stack tag tracker.
324
//
325
public void endElement(
326         ElementPSVInfoset infoSet,
327         Stack JavaDoc tagStack)
328     {
329
330         // Clean up the stack...
331
tagStack.pop();
332
333     }
334 }
335
Popular Tags