1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48:
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57:
58: import ;
59:
60:
61:
62:
102: public class XIncludeFilter extends EventFilter implements Locator
103: {
104: private Hashtable extEntities = new Hashtable (5, 5);
105: private int ignoreCount;
106: private Stack uris = new Stack ();
107: private Locator locator;
108: private Vector inclusions = new Vector (5, 5);
109: private boolean savingPrefixes;
110:
111:
113: public XIncludeFilter (EventConsumer next)
114: throws SAXException
115: {
116: super (next);
117: setContentHandler (this);
118:
119: setProperty (DECL_HANDLER, this);
120: setProperty (LEXICAL_HANDLER, this);
121: }
122:
123: private void fatal (SAXParseException e) throws SAXException
124: {
125: ErrorHandler eh;
126:
127: eh = getErrorHandler ();
128: if (eh != null)
129: eh.fatalError (e);
130: throw e;
131: }
132:
133:
136: public void setDocumentLocator (Locator locator)
137: {
138: this.locator = locator;
139: super.setDocumentLocator (this);
140: }
141:
142:
143: public String getSystemId ()
144: { return (locator == null) ? null : locator.getSystemId (); }
145:
146: public String getPublicId ()
147: { return (locator == null) ? null : locator.getPublicId (); }
148:
149: public int getLineNumber ()
150: { return (locator == null) ? -1 : locator.getLineNumber (); }
151:
152: public int getColumnNumber ()
153: { return (locator == null) ? -1 : locator.getColumnNumber (); }
154:
155:
159: public void setSavingPrefixes (boolean flag)
160: { savingPrefixes = flag; }
161:
162:
168: public boolean isSavingPrefixes ()
169: { return savingPrefixes; }
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181: private String addMarker (String uri)
182: throws SAXException
183: {
184: if (locator != null && locator.getSystemId () != null)
185: uri = locator.getSystemId ();
186:
187:
188: if (uri == null)
189: fatal (new SAXParseException ("Entity URI is unknown", locator));
190:
191: try {
192: URL url = new URL (uri);
193:
194: uri = url.toString ();
195: if (inclusions.contains (uri))
196: fatal (new SAXParseException (
197: "XInclude, circular inclusion", locator));
198: inclusions.addElement (uri);
199: uris.push (url);
200: } catch (IOException e) {
201:
202: fatal (new SAXParseException ("parser bug: relative URI",
203: locator, e));
204: }
205: return uri;
206: }
207:
208: private void pop (String uri)
209: {
210: inclusions.removeElement (uri);
211: uris.pop ();
212: }
213:
214:
215:
216:
217: public void startDocument () throws SAXException
218: {
219: ignoreCount = 0;
220: addMarker (null);
221: super.startDocument ();
222: }
223:
224: public void endDocument () throws SAXException
225: {
226: inclusions.setSize (0);
227: extEntities.clear ();
228: uris.setSize (0);
229: super.endDocument ();
230: }
231:
232:
233:
234:
235: public void externalEntityDecl (String name,
236: String publicId, String systemId)
237: throws SAXException
238: {
239: if (name.charAt (0) == '%')
240: return;
241: try {
242: URL url = new URL (locator.getSystemId ());
243: systemId = new URL (url, systemId).toString ();
244: } catch (IOException e) {
245:
246: }
247: extEntities.put (name, systemId);
248: }
249:
250: public void startEntity (String name)
251: throws SAXException
252: {
253: if (ignoreCount != 0) {
254: ignoreCount++;
255: return;
256: }
257:
258: String uri = (String) extEntities.get (name);
259: if (uri != null)
260: addMarker (uri);
261: super.startEntity (name);
262: }
263:
264: public void endEntity (String name)
265: throws SAXException
266: {
267: if (ignoreCount != 0) {
268: if (--ignoreCount != 0)
269: return;
270: }
271:
272: String uri = (String) extEntities.get (name);
273:
274: if (uri != null)
275: pop (uri);
276: super.endEntity (name);
277: }
278:
279:
280:
281:
282:
283: public void
284: startElement (String uri, String localName, String qName, Attributes atts)
285: throws SAXException
286: {
287: if (ignoreCount != 0) {
288: ignoreCount++;
289: return;
290: }
291:
292: URL baseURI = (URL) uris.peek ();
293: String base;
294:
295: base = atts.getValue ("http://www.w3.org/XML/1998/namespace", "base");
296: if (base == null)
297: uris.push (baseURI);
298: else {
299: URL url;
300:
301: if (base.indexOf ('#') != -1)
302: fatal (new SAXParseException (
303: "xml:base with fragment: " + base,
304: locator));
305:
306: try {
307: baseURI = new URL (baseURI, base);
308: uris.push (baseURI);
309: } catch (Exception e) {
310: fatal (new SAXParseException (
311: "xml:base with illegal uri: " + base,
312: locator, e));
313: }
314: }
315:
316: if (!"http://www.w3.org/2001/XInclude".equals (uri)) {
317: super.startElement (uri, localName, qName, atts);
318: return;
319: }
320:
321: if ("include".equals (localName)) {
322: String href = atts.getValue ("href");
323: String parse = atts.getValue ("parse");
324: String encoding = atts.getValue ("encoding");
325: URL url = (URL) uris.peek ();
326: SAXParseException x = null;
327:
328: if (href == null)
329: fatal (new SAXParseException (
330: "XInclude missing href",
331: locator));
332: if (href.indexOf ('#') != -1)
333: fatal (new SAXParseException (
334: "XInclude with fragment: " + href,
335: locator));
336:
337: if (parse == null || "xml".equals (parse))
338: x = xinclude (url, href);
339: else if ("text".equals (parse))
340: x = readText (url, href, encoding);
341: else
342: fatal (new SAXParseException (
343: "unknown XInclude parsing mode: " + parse,
344: locator));
345: if (x == null) {
346:
347: ignoreCount++;
348: return;
349: }
350:
351:
352:
353:
354: fatal (x);
355:
356: } else if ("fallback".equals (localName)) {
357: fatal (new SAXParseException (
358: "illegal top level XInclude 'fallback' element",
359: locator));
360: } else {
361: ErrorHandler eh = getErrorHandler ();
362:
363:
364: if (eh != null)
365: eh.warning (new SAXParseException (
366: "unrecognized toplevel XInclude element: " + localName,
367: locator));
368: super.startElement (uri, localName, qName, atts);
369: }
370: }
371:
372: public void endElement (String uri, String localName, String qName)
373: throws SAXException
374: {
375: if (ignoreCount != 0) {
376: if (--ignoreCount != 0)
377: return;
378: }
379:
380: uris.pop ();
381: if (!("http://www.w3.org/2001/XInclude".equals (uri)
382: && "include".equals (localName)))
383: super.endElement (uri, localName, qName);
384: }
385:
386:
387:
388:
389: public void characters (char ch [], int start, int length)
390: throws SAXException
391: {
392: if (ignoreCount == 0)
393: super.characters (ch, start, length);
394: }
395:
396: public void processingInstruction (String target, String value)
397: throws SAXException
398: {
399: if (ignoreCount == 0)
400: super.processingInstruction (target, value);
401: }
402:
403: public void ignorableWhitespace (char ch [], int start, int length)
404: throws SAXException
405: {
406: if (ignoreCount == 0)
407: super.ignorableWhitespace (ch, start, length);
408: }
409:
410: public void comment (char ch [], int start, int length)
411: throws SAXException
412: {
413: if (ignoreCount == 0)
414: super.comment (ch, start, length);
415: }
416:
417: public void startCDATA () throws SAXException
418: {
419: if (ignoreCount == 0)
420: super.startCDATA ();
421: }
422:
423: public void endCDATA () throws SAXException
424: {
425: if (ignoreCount == 0)
426: super.endCDATA ();
427: }
428:
429: public void startPrefixMapping (String prefix, String uri)
430: throws SAXException
431: {
432: if (ignoreCount == 0)
433: super.startPrefixMapping (prefix, uri);
434: }
435:
436: public void endPrefixMapping (String prefix) throws SAXException
437: {
438: if (ignoreCount == 0)
439: super.endPrefixMapping (prefix);
440: }
441:
442: public void skippedEntity (String name) throws SAXException
443: {
444: if (ignoreCount == 0)
445: super.skippedEntity (name);
446: }
447:
448:
449: void setLocator (Locator l) { locator = l; }
450: Locator getLocator () { return locator; }
451:
452:
453:
454:
455:
456:
457: private class Scrubber extends EventFilter
458: {
459: Scrubber (EventFilter f)
460: throws SAXException
461: {
462:
463: super (f);
464:
465:
466: super.setContentHandler (this);
467: super.setProperty (LEXICAL_HANDLER, this);
468:
469:
470: super.setDTDHandler (null);
471: super.setProperty (DECL_HANDLER, null);
472: }
473:
474:
475:
476: public void setDocumentLocator (Locator l)
477: { setLocator (l); }
478: public void startDocument ()
479: { }
480: public void endDocument ()
481: { }
482:
483: private void reject (String message) throws SAXException
484: { fatal (new SAXParseException (message, getLocator ())); }
485:
486:
487: public void startDTD (String root, String publicId, String systemId)
488: throws SAXException
489: { reject ("XIncluded DTD: " + systemId); }
490: public void endDTD ()
491: throws SAXException
492: { reject ("XIncluded DTD"); }
493:
494: public void skippedEntity (String name) throws SAXException
495: { reject ("XInclude skipped entity: " + name); }
496:
497:
498: }
499:
500:
501:
502: private SAXParseException xinclude (URL url, String href)
503: throws SAXException
504: {
505: XMLReader helper;
506: Scrubber scrubber;
507: Locator savedLocator = locator;
508:
509:
510:
511: helper = XMLReaderFactory.createXMLReader ();
512: helper.setErrorHandler (getErrorHandler ());
513: helper.setFeature (FEATURE_URI + "namespace-prefixes", true);
514:
515:
516: scrubber = new Scrubber (this);
517: locator = null;
518: bind (helper, scrubber);
519:
520:
521: try {
522: url = new URL (url, href);
523: href = url.toString ();
524:
525: if (inclusions.contains (href))
526: fatal (new SAXParseException (
527: "XInclude, circular inclusion", locator));
528:
529: inclusions.addElement (href);
530: uris.push (url);
531: helper.parse (new InputSource (href));
532: return null;
533: } catch (java.io.IOException e) {
534: return new SAXParseException (href, locator, e);
535: } finally {
536: pop (href);
537: locator = savedLocator;
538: }
539: }
540:
541:
542:
543: private SAXParseException readText (URL url, String href, String encoding)
544: throws SAXException
545: {
546: InputStream in = null;
547:
548: try {
549: URLConnection conn;
550: InputStreamReader reader;
551: char buf [] = new char [4096];
552: int count;
553:
554: url = new URL (url, href);
555: conn = url.openConnection ();
556: in = conn.getInputStream ();
557: if (encoding == null)
558: encoding = Resolver.getEncoding (conn.getContentType ());
559: if (encoding == null) {
560: ErrorHandler eh = getErrorHandler ();
561: if (eh != null)
562: eh.warning (new SAXParseException (
563: "guessing text encoding for URL: " + url,
564: locator));
565: reader = new InputStreamReader (in);
566: } else
567: reader = new InputStreamReader (in, encoding);
568:
569: while ((count = reader.read (buf, 0, buf.length)) != -1)
570: super.characters (buf, 0, count);
571: in.close ();
572: return null;
573: } catch (IOException e) {
574: return new SAXParseException (
575: "can't XInclude text",
576: locator, e);
577: }
578: }
579: }