1 /* XIncludeFilter.java --
2    Copyright (C) 2005  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.stream;
39 
40 import java.io.InputStream;
41 import java.io.InputStreamReader;
42 import java.io.IOException;
43 import java.io.Reader;
44 import java.net.HttpURLConnection;
45 import java.net.URL;
46 import java.net.URLConnection;
47 import java.util.HashSet;
48 import java.util.NoSuchElementException;
49 import java.util.StringTokenizer;
50 import javax.xml.namespace.QName;
51 import javax.xml.parsers.DocumentBuilder;
52 import javax.xml.parsers.DocumentBuilderFactory;
53 import javax.xml.parsers.ParserConfigurationException;
54 import javax.xml.stream.XMLStreamConstants;
55 import javax.xml.stream.XMLStreamException;
56 import javax.xml.stream.XMLStreamReader;
57 import javax.xml.stream.util.StreamReaderDelegate;
58 
59 import org.w3c.dom.Attr;
60 import org.w3c.dom.Document;
61 import org.w3c.dom.DOMImplementation;
62 import org.w3c.dom.NamedNodeMap;
63 import org.w3c.dom.Node;
64 import org.w3c.dom.ProcessingInstruction;
65 import org.w3c.dom.TypeInfo;
66 import org.w3c.dom.traversal.DocumentTraversal;
67 import org.w3c.dom.traversal.NodeFilter;
68 import org.w3c.dom.traversal.TreeWalker;
69 import org.w3c.dom.xpath.XPathEvaluator;
70 import org.w3c.dom.xpath.XPathNSResolver;
71 import org.w3c.dom.xpath.XPathResult;
72 import org.xml.sax.SAXException;
73 
74 /**
75  * StAX filter for performing XInclude processing.
76  *
77  * @see http://www.w3.org/TR/xinclude/
78  * @see http://www.w3.org/TR/xptr-framework/
79  * @see http://www.w3.org/TR/xptr-element/
80  *
81  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
82  */
83 class XIncludeFilter
84   extends StreamReaderDelegate
85 {
86 
87   static final String XINCLUDE_NS_URI = "http://www.w3.org/2001/XInclude";
88   static final int SHOW_FLAGS =
89     NodeFilter.SHOW_CDATA_SECTION |
90     NodeFilter.SHOW_COMMENT |
91     NodeFilter.SHOW_ELEMENT |
92     NodeFilter.SHOW_ENTITY_REFERENCE |
93     NodeFilter.SHOW_PROCESSING_INSTRUCTION |
94     NodeFilter.SHOW_TEXT;
95 
96   final String systemId;
97   final boolean namespaceAware;
98   final boolean validating;
99   final boolean expandERefs;
100   String href;
101   int event;
102   boolean included;
103   XPathResult result;
104   int snapshotIndex;
105   Node current;
106   TreeWalker walker;
107   HashSet seen = new HashSet();
108   boolean backtracking;
109   boolean lookahead;
110 
111   Reader includedText;
112   char[] buf;
113   int len = -1;
114   boolean inInclude, inFallback, seenFallback;
115 
116   DocumentBuilder builder;
117 
XIncludeFilter(XMLStreamReader reader, String systemId, boolean namespaceAware, boolean validating, boolean expandERefs)118   XIncludeFilter(XMLStreamReader reader, String systemId,
119                  boolean namespaceAware, boolean validating,
120                  boolean expandERefs)
121   {
122     super(reader);
123     this.systemId = XMLParser.absolutize(null, systemId);
124     this.namespaceAware = namespaceAware;
125     this.validating = validating;
126     this.expandERefs = expandERefs;
127   }
128 
getAttributeCount()129   public int getAttributeCount()
130   {
131     if (current != null)
132       {
133         NamedNodeMap attrs = current.getAttributes();
134         return (attrs == null) ? 0 : attrs.getLength();
135       }
136     return super.getAttributeCount();
137   }
138 
getAttributeLocalName(int index)139   public String getAttributeLocalName(int index)
140   {
141     if (current != null)
142       {
143         NamedNodeMap attrs = current.getAttributes();
144         if (attrs == null)
145          return null;
146         Node attr = attrs.item(index);
147         return attr.getLocalName();
148       }
149     return super.getAttributeLocalName(index);
150   }
151 
getAttributeNamespace(int index)152   public String getAttributeNamespace(int index)
153   {
154     if (current != null)
155       {
156         NamedNodeMap attrs = current.getAttributes();
157         if (attrs == null)
158          return null;
159         Node attr = attrs.item(index);
160         return attr.getNamespaceURI();
161       }
162     return super.getAttributeNamespace(index);
163   }
164 
getAttributePrefix(int index)165   public String getAttributePrefix(int index)
166   {
167     if (current != null)
168       {
169         NamedNodeMap attrs = current.getAttributes();
170         if (attrs == null)
171          return null;
172         Node attr = attrs.item(index);
173         return attr.getPrefix();
174       }
175     return super.getAttributePrefix(index);
176   }
177 
getAttributeName(int index)178   public QName getAttributeName(int index)
179   {
180     if (current != null)
181       {
182         NamedNodeMap attrs = current.getAttributes();
183         if (attrs == null)
184          return null;
185         Node attr = attrs.item(index);
186         String localName = attr.getLocalName();
187         String uri = attr.getNamespaceURI();
188         String prefix = attr.getPrefix();
189         return new QName(uri, localName, prefix);
190       }
191     return super.getAttributeName(index);
192   }
193 
getAttributeType(int index)194   public String getAttributeType(int index)
195   {
196     if (current != null)
197       {
198         NamedNodeMap attrs = current.getAttributes();
199         if (attrs == null)
200          return null;
201         Attr attr = (Attr) attrs.item(index);
202         TypeInfo ti = attr.getSchemaTypeInfo();
203         return (ti == null) ? "CDATA" : ti.getTypeName();
204       }
205     return super.getAttributeType(index);
206   }
207 
isAttributeSpecified(int index)208   public boolean isAttributeSpecified(int index)
209   {
210     if (current != null)
211       {
212         NamedNodeMap attrs = current.getAttributes();
213         if (attrs == null)
214           return false;
215         Attr attr = (Attr) attrs.item(index);
216         return attr.getSpecified();
217       }
218     return super.isAttributeSpecified(index);
219   }
220 
getAttributeValue(int index)221   public String getAttributeValue(int index)
222   {
223     if (current != null)
224       {
225         NamedNodeMap attrs = current.getAttributes();
226         if (attrs == null)
227          return null;
228         Node attr = attrs.item(index);
229         return attr.getNodeValue();
230       }
231     return super.getAttributeValue(index);
232   }
233 
getAttributeValue(String uri, String localName)234   public String getAttributeValue(String uri, String localName)
235   {
236     if (current != null)
237       {
238         NamedNodeMap attrs = current.getAttributes();
239         if (attrs == null)
240          return null;
241         Node attr = attrs.getNamedItemNS(uri, localName);
242         return (attr == null) ? null : attr.getNodeValue();
243       }
244     return super.getAttributeValue(uri, localName);
245   }
246 
getElementText()247   public String getElementText()
248     throws XMLStreamException
249   {
250     if (current != null)
251       return current.getTextContent();
252     return super.getElementText();
253   }
254 
getEventType()255   public int getEventType()
256   {
257     return event;
258   }
259 
getLocalName()260   public String getLocalName()
261   {
262     if (current != null)
263       return current.getLocalName();
264     return super.getLocalName();
265   }
266 
getName()267   public QName getName()
268   {
269     if (current != null)
270       {
271         String localName = current.getLocalName();
272         String uri = current.getNamespaceURI();
273         String prefix = current.getPrefix();
274         return new QName(uri, localName, prefix);
275       }
276     return super.getName();
277   }
278 
getNamespaceURI()279   public String getNamespaceURI()
280   {
281     if (current != null)
282       return current.getNamespaceURI();
283     return super.getNamespaceURI();
284   }
285 
286   // TODO namespaces
287 
getPIData()288   public String getPIData()
289   {
290     if (current != null)
291       return ((ProcessingInstruction) current).getData();
292     return super.getPIData();
293   }
294 
getPITarget()295   public String getPITarget()
296   {
297     if (current != null)
298       return ((ProcessingInstruction) current).getTarget();
299     return super.getPITarget();
300   }
301 
getPrefix()302   public String getPrefix()
303   {
304     if (current != null)
305       return current.getPrefix();
306     return super.getPrefix();
307   }
308 
getText()309   public String getText()
310   {
311     if (current != null)
312       return current.getNodeValue();
313     if (walker != null)
314       {
315         Node n = walker.getCurrentNode();
316         if (n != null)
317           return n.getTextContent();
318       }
319     if (buf != null)
320       return new String(buf, 0, len);
321     return super.getText();
322   }
323 
getTextCharacters()324   public char[] getTextCharacters()
325   {
326     if (current != null)
327       {
328         buf = current.getNodeValue().toCharArray();
329         len = buf.length;
330       }
331     if (buf != null)
332       return buf;
333     return super.getTextCharacters();
334   }
335 
getTextCharacters(int sourceStart, char[] target, int targetStart, int length)336   public int getTextCharacters(int sourceStart, char[] target,
337                                int targetStart, int length)
338     throws XMLStreamException
339   {
340     if (current != null)
341       {
342         buf = current.getNodeValue().toCharArray();
343         len = buf.length;
344       }
345     if (buf != null)
346       {
347         int max = Math.min(len - sourceStart, length);
348         if (max > 0)
349           System.arraycopy(buf, sourceStart, target, targetStart, max);
350         return max;
351       }
352     return super.getTextCharacters(sourceStart, target, targetStart, length);
353   }
354 
getTextLength()355   public int getTextLength()
356   {
357     if (current != null)
358       {
359         buf = current.getNodeValue().toCharArray();
360         len = buf.length;
361       }
362     if (buf != null)
363       return len;
364     return super.getTextLength();
365   }
366 
getTextStart()367   public int getTextStart()
368   {
369     if (current != null)
370       {
371         buf = current.getNodeValue().toCharArray();
372         len = buf.length;
373       }
374     if (buf != null)
375       return 0;
376     return super.getTextStart();
377   }
378 
hasNext()379   public boolean hasNext()
380     throws XMLStreamException
381   {
382     if (!lookahead)
383       {
384         try
385           {
386             next();
387           }
388         catch (NoSuchElementException e)
389           {
390             event = -1;
391           }
392         lookahead = true;
393       }
394     return (event != -1);
395   }
396 
next()397   public int next()
398     throws XMLStreamException
399   {
400     if (lookahead)
401       {
402         lookahead = false;
403         return event;
404       }
405     buf = null;
406     len = 0;
407     if (walker != null)
408       {
409         Node c = walker.getCurrentNode();
410         Node n = null;
411         if (c.getNodeType() == Node.ELEMENT_NODE)
412           {
413             boolean isStartElement = !seen.contains(c);
414             if (isStartElement)
415               {
416                 seen.add(c);
417                 current = c;
418                 event = XMLStreamConstants.START_ELEMENT;
419                 return event;
420               }
421             else if (backtracking)
422               {
423                 n = walker.nextSibling();
424                 if (n != null)
425                   backtracking = false;
426               }
427             else
428               {
429                 n = walker.firstChild();
430                 if (n == null)
431                   n = walker.nextSibling();
432               }
433           }
434         else
435           {
436             n = walker.firstChild();
437             if (n == null)
438               n = walker.nextSibling();
439           }
440         if (n == null)
441           {
442             current = walker.parentNode();
443             if (current != null && current.getNodeType() == Node.ELEMENT_NODE)
444               {
445                 // end-element
446                 backtracking = true;
447                 event = XMLStreamConstants.END_ELEMENT;
448                 return event;
449               }
450             else
451               {
452                 walker = null;
453                 current = null;
454               }
455           }
456         else
457           {
458             current = n;
459             switch (n.getNodeType())
460               {
461               case Node.ELEMENT_NODE:
462                 return next();
463               case Node.TEXT_NODE:
464                 String text = n.getNodeValue();
465                 buf = text.toCharArray();
466                 len = buf.length;
467                 event = isSpace(buf, len) ?
468                   XMLStreamConstants.SPACE :
469                   XMLStreamConstants.CHARACTERS;
470                 return event;
471               case Node.CDATA_SECTION_NODE:
472                 event = XMLStreamConstants.CDATA;
473                 return event;
474               case Node.COMMENT_NODE:
475                 event = XMLStreamConstants.COMMENT;
476                 return event;
477               case Node.PROCESSING_INSTRUCTION_NODE:
478                 event = XMLStreamConstants.PROCESSING_INSTRUCTION;
479                 return event;
480               case Node.ENTITY_REFERENCE_NODE:
481                 event = XMLStreamConstants.ENTITY_REFERENCE;
482                 return event;
483               default:
484                 throw new IllegalStateException();
485               }
486           }
487       }
488     if (result != null)
489       {
490         switch (result.getResultType())
491           {
492           case XPathResult.BOOLEAN_TYPE:
493             boolean bval = result.getBooleanValue();
494             String btext = bval ? "true" : "false";
495             buf = btext.toCharArray();
496             len = buf.length;
497             result = null;
498             event = XMLStreamConstants.CHARACTERS;
499             return event;
500           case XPathResult.NUMBER_TYPE:
501             double nval = result.getNumberValue();
502             String ntext = Double.toString(nval);
503             buf = ntext.toCharArray();
504             len = buf.length;
505             result = null;
506             event = XMLStreamConstants.CHARACTERS;
507             return event;
508           case XPathResult.STRING_TYPE:
509             String stext = result.getStringValue();
510             buf = stext.toCharArray();
511             len = buf.length;
512             result = null;
513             event = isSpace(buf, len) ?
514               XMLStreamConstants.SPACE :
515               XMLStreamConstants.CHARACTERS;
516             return event;
517           case XPathResult.ANY_UNORDERED_NODE_TYPE:
518           case XPathResult.FIRST_ORDERED_NODE_TYPE:
519             Node n1 = result.getSingleNodeValue();
520             Document d1 = getDocument(n1);
521             walker = getDocumentTraversal(d1)
522               .createTreeWalker(n1, SHOW_FLAGS, null, expandERefs);
523             result = null;
524             return next();
525           case XPathResult.ORDERED_NODE_ITERATOR_TYPE:
526           case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
527             Node n2 = result.iterateNext();
528             if (n2 == null)
529               {
530                 result = null;
531                 return next();
532               }
533             Document d2 = getDocument(n2);
534             walker = getDocumentTraversal(d2)
535               .createTreeWalker(n2, SHOW_FLAGS, null, expandERefs);
536             return next();
537           case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE:
538           case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE:
539             Node n3 = result.snapshotItem(snapshotIndex++);
540             if (n3 == null)
541               {
542                 result = null;
543                 return next();
544               }
545             Document d3 = getDocument(n3);
546             walker = getDocumentTraversal(d3)
547               .createTreeWalker(n3, SHOW_FLAGS, null, expandERefs);
548             return next();
549           default:
550             throw new IllegalStateException();
551           }
552       }
553     if (includedText != null)
554       {
555         // fill buffer
556         if (buf == null)
557           buf = new char[2048];
558         try
559           {
560             len = includedText.read(buf, 0, buf.length);
561             if (len == -1)
562               {
563                 includedText = null;
564                 buf = null;
565                 return next();
566               }
567             // chars or space?
568             return (event = isSpace(buf, len) ?
569                     XMLStreamConstants.SPACE :
570                     XMLStreamConstants.CHARACTERS);
571           }
572         catch (IOException e)
573           {
574             XMLStreamException e2 = new XMLStreamException(e.getMessage());
575             e2.initCause(e);
576             throw e2;
577           }
578       }
579     event = super.next();
580     switch (event)
581       {
582       case XMLStreamConstants.START_ELEMENT:
583         String uri = getNamespaceURI();
584         if (XINCLUDE_NS_URI.equals(uri))
585           {
586             String localName = getLocalName();
587             if ("include".equals(localName))
588               {
589                 href = getAttributeValue(null, "href");
590                 String parse = getAttributeValue(null, "parse");
591                 String xpointer = getAttributeValue(null, "xpointer");
592                 String encoding = getAttributeValue(null, "encoding");
593                 String accept = getAttributeValue(null, "accept");
594                 String acceptLanguage = getAttributeValue(null,
595                                                           "accept-language");
596                 if (includeResource(href, parse, xpointer, encoding,
597                                     accept, acceptLanguage))
598                   {
599                     // Skip to xi:include end-element event
600                     int depth = 0;
601                     while (depth >= 0)
602                       {
603                         event = super.next();
604                         switch (event)
605                           {
606                           case XMLStreamConstants.START_ELEMENT:
607                             depth++;
608                             break;
609                           case XMLStreamConstants.END_ELEMENT:
610                             depth--;
611                           }
612                       }
613                   }
614                 else
615                   inInclude = true;
616               }
617             else if (inInclude && "fallback".equals(localName))
618               {
619                 if (!seenFallback)
620                   inFallback = seenFallback = true;
621                 else
622                   throw new XMLStreamException("duplicate xi:fallback element");
623               }
624             else if (inInclude)
625               {
626                 throw new XMLStreamException("illegal xi element '" +
627                                              localName + "'");
628               }
629             return next();
630           }
631         break;
632       case XMLStreamConstants.END_ELEMENT:
633         String uri2 = getNamespaceURI();
634         if (XINCLUDE_NS_URI.equals(uri2))
635           {
636             String localName = getLocalName();
637             if ("include".equals(localName))
638               {
639                 if (!seenFallback && included)
640                   {
641                     String msg = "Unable to read " + href +
642                       " and no xi:fallback element present";
643                     throw new XMLStreamException(msg);
644                   }
645                 included = false;
646                 href = null;
647                 inInclude = inFallback = seenFallback = false;
648               }
649             else if ("fallback".equals(localName))
650               inFallback = false;
651             return next();
652           }
653         break;
654       }
655     if (inInclude && !inFallback)
656       return next();
657     return event;
658   }
659 
isSpace(char[] text, int len)660   boolean isSpace(char[] text, int len)
661   {
662     boolean space = true;
663     for (int i = 0; i < len; i++)
664       {
665         char c = text[i];
666         if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
667           {
668             space = false;
669             break;
670           }
671       }
672     return space;
673   }
674 
getBaseURI()675   String getBaseURI()
676   {
677     String base = (String) getParent().getProperty("gnu.xml.stream.baseURI");
678     return (base == null) ? systemId : base;
679   }
680 
includeResource(String href, String parse, String xpointer, String encoding, String accept, String acceptLanguage)681   boolean includeResource(String href, String parse, String xpointer,
682                           String encoding, String accept,
683                           String acceptLanguage)
684   {
685     included = false;
686     try
687       {
688         if (xpointer != null)
689           throw new XMLStreamException("xpointer attribute not yet supported");
690         String base = getBaseURI();
691         if (href == null || "".equals(href))
692           href = base;
693         else
694           href = XMLParser.absolutize(base, href);
695         if (parse == null || "xml".equals(parse))
696           {
697             seen.clear();
698             result = null;
699             snapshotIndex = 0;
700             walker = null;
701             current = null;
702             backtracking = false;
703 
704             URLConnection connection = getURLConnection(href, accept,
705                                                         acceptLanguage);
706             InputStream in = connection.getInputStream();
707             Document doc = getDocumentBuilder().parse(in, href);
708             DocumentTraversal dt = getDocumentTraversal(doc);
709             if (xpointer == null)
710               {
711                 result = null;
712                 Node item = doc.getDocumentElement();
713                 walker = dt.createTreeWalker(item, SHOW_FLAGS, null,
714                                              expandERefs);
715               }
716             else
717               {
718                 result = null;
719                 snapshotIndex = 0;
720                 walker = null;
721                 // shorthand or scheme-based?
722                 int lpi = xpointer.indexOf('(');
723                 int rpi = xpointer.indexOf(')', lpi);
724                 if (lpi != -1 && rpi != -1)
725                   {
726                     String scheme = xpointer.substring(0, lpi);
727                     if ("element".equals(scheme))
728                       {
729                         // element() scheme
730                         String elementSchemeData =
731                           xpointer.substring(lpi + 1, rpi);
732                         Node item = doc;
733                         int si = elementSchemeData.indexOf('/');
734                         if (si == -1)
735                           {
736                             if (elementSchemeData.length() > 0)
737                               item = doc.getElementById(elementSchemeData);
738                           }
739                         else
740                           {
741                             if (si > 0)
742                               {
743                                 String context =
744                                   elementSchemeData.substring(0, si);
745                                 item = doc.getElementById(context);
746                                 elementSchemeData =
747                                   elementSchemeData.substring(si + 1);
748                               }
749                             StringTokenizer st =
750                               new StringTokenizer(elementSchemeData, "/");
751                             while (st.hasMoreTokens() && item != null)
752                               {
753                                 int n = Integer.parseInt(st.nextToken());
754                                 Node ctx = item.getFirstChild();
755                                 int count = 1;
756                                 while (ctx != null && count++ < n)
757                                   ctx = ctx.getNextSibling();
758                                 item = ctx;
759                               }
760                           }
761                         walker = dt.createTreeWalker(item, SHOW_FLAGS, null,
762                                                      expandERefs);
763                         included = true;
764                       }
765                     else if ("xpointer".equals(scheme))
766                       {
767                         xpointer = xpointer.substring(lpi + 1, rpi);
768                         XPathEvaluator eval = getXPathEvaluator(doc);
769                         XPathNSResolver resolver = eval.createNSResolver(doc);
770                         result =
771                           (XPathResult) eval.evaluate(xpointer, doc,
772                                                       resolver,
773                                                       XPathResult.ANY_TYPE,
774                                                       null);
775                         // TODO xpointer() scheme functions
776                         included = true;
777                       }
778                     else
779                       {
780                         String msg = "Unknown XPointer scheme: " + scheme;
781                         throw new XMLStreamException(msg);
782                       }
783                   }
784                 else
785                   {
786                     Node item = doc.getElementById(xpointer);
787                     walker = dt.createTreeWalker(item, SHOW_FLAGS, null,
788                                                  expandERefs);
789                     included = true;
790                   }
791               }
792           }
793         else if ("text".equals(parse))
794           {
795             URLConnection connection = getURLConnection(href, accept,
796                                                         acceptLanguage);
797             InputStream in = connection.getInputStream();
798             if (encoding == null)
799               {
800                 encoding = connection.getContentEncoding();
801                 if (encoding == null)
802                   {
803                     String contentType = connection.getContentType();
804                     if (contentType != null)
805                       encoding = getParameter(contentType, "charset");
806                   }
807               }
808             if (encoding == null)
809               includedText = new InputStreamReader(in, "UTF-8");
810             else
811               includedText = new InputStreamReader(in, encoding);
812             included = true;
813           }
814         else
815           throw new XMLStreamException("value of 'parse' attribute must be "+
816                                        "'xml' or 'text'");
817         return true;
818       }
819     catch (IOException e)
820       {
821         return false;
822       }
823     catch (XMLStreamException e)
824       {
825         return false;
826       }
827     catch (SAXException e)
828       {
829         return false;
830       }
831   }
832 
getURLConnection(String href, String accept, String acceptLanguage)833   URLConnection getURLConnection(String href, String accept,
834                                  String acceptLanguage)
835     throws IOException
836   {
837     URL url = new URL(href);
838     URLConnection connection = url.openConnection();
839     if (connection instanceof HttpURLConnection)
840       {
841         HttpURLConnection http = (HttpURLConnection) connection;
842         http.setInstanceFollowRedirects(true);
843         if (accept != null)
844           http.setRequestProperty("Accept", accept);
845         if (acceptLanguage != null)
846           http.setRequestProperty("Accept-Language", acceptLanguage);
847       }
848     return connection;
849   }
850 
getDocument(Node node)851   Document getDocument(Node node)
852   {
853     if (node.getNodeType() == Node.DOCUMENT_NODE)
854       return (Document) node;
855     return node.getOwnerDocument();
856   }
857 
getDocumentBuilder()858   DocumentBuilder getDocumentBuilder()
859     throws XMLStreamException
860   {
861     if (builder == null)
862       {
863         try
864           {
865             DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
866             f.setXIncludeAware(true);
867             f.setNamespaceAware(namespaceAware);
868             f.setValidating(validating);
869             builder = f.newDocumentBuilder();
870           }
871         catch (ParserConfigurationException e)
872           {
873             XMLStreamException e2 = new XMLStreamException(e.getMessage());
874             e2.initCause(e);
875             throw e2;
876           }
877       }
878     builder.reset();
879     return builder;
880   }
881 
getDocumentTraversal(Document doc)882   DocumentTraversal getDocumentTraversal(Document doc)
883     throws XMLStreamException
884   {
885     DOMImplementation dom = doc.getImplementation();
886     if (!dom.hasFeature("Traversal", "2.0"))
887       throw new XMLStreamException("Traversal not supported");
888     return (DocumentTraversal) doc;
889   }
890 
getXPathEvaluator(Document doc)891   XPathEvaluator getXPathEvaluator(Document doc)
892     throws XMLStreamException
893   {
894     DOMImplementation dom = doc.getImplementation();
895     if (!dom.hasFeature("XPath", "3.0"))
896       throw new XMLStreamException("XPath not supported");
897     return (XPathEvaluator) doc;
898   }
899 
getParameter(String contentType, String name)900   static String getParameter(String contentType, String name)
901   {
902     StringTokenizer st = new StringTokenizer(contentType, " ;");
903     if (st.hasMoreTokens())
904       st.nextToken();
905     while (st.hasMoreTokens())
906       {
907         String token = st.nextToken();
908         int ei = token.indexOf('=');
909         if (ei != -1)
910           {
911             String key = token.substring(0, ei);
912             if (key.equals(name))
913               {
914                 String value = token.substring(ei + 1);
915                 int len = value.length();
916                 if (len > 1 &&
917                     value.charAt(0) == '"' &&
918                     value.charAt(len - 1) == '"')
919                   value = value.substring(1, len - 1);
920                 else if (len > 1 &&
921                          value.charAt(0) == '\'' &&
922                          value.charAt(len - 1) == '\'')
923                   value = value.substring(1, len - 1);
924                 return value;
925               }
926           }
927       }
928     return null;
929   }
930 
931 }
932