View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 1999-2004 The Apache Software Foundation.
7    *
8    * Licensed under the Apache License, Version 2.0 (the "License");
9    * you may not use this file except in compliance with the License.
10   * You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  /*
21   * $Id: StylesheetPIHandler.java,v 1.2.4.1 2005/09/15 08:15:57 suresh_emailid Exp $
22   */
23  package com.sun.org.apache.xml.internal.utils;
24  
25  import java.util.StringTokenizer;
26  import java.util.Vector;
27  
28  import javax.xml.transform.Source;
29  import javax.xml.transform.TransformerException;
30  import javax.xml.transform.URIResolver;
31  import javax.xml.transform.sax.SAXSource;
32  
33  import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
34  
35  import org.xml.sax.Attributes;
36  import org.xml.sax.InputSource;
37  import org.xml.sax.helpers.DefaultHandler;
38  
39  /**
40   * Search for the xml-stylesheet processing instructions in an XML document.
41   * @see <a href="http://www.w3.org/TR/xml-stylesheet/">Associating Style Sheets with XML documents, Version 1.0</a>
42   */
43  public class StylesheetPIHandler extends DefaultHandler
44  {
45    /** The baseID of the document being processed.  */
46    String m_baseID;
47  
48    /** The desired media criteria. */
49    String m_media;
50  
51    /** The desired title criteria.  */
52    String m_title;
53  
54    /** The desired character set criteria.   */
55    String m_charset;
56  
57    /** A list of SAXSource objects that match the criteria.  */
58    Vector m_stylesheets = new Vector();
59  
60    // Add code to use a URIResolver. Patch from Dmitri Ilyin.
61  
62    /**
63     * The object that implements the URIResolver interface,
64     * or null.
65     */
66    URIResolver m_uriResolver;
67  
68    /**
69     * Get the object that will be used to resolve URIs in href
70     * in xml-stylesheet processing instruction.
71     *
72     * @param resolver An object that implements the URIResolver interface,
73     * or null.
74     */
75    public void setURIResolver(URIResolver resolver)
76    {
77      m_uriResolver = resolver;
78    }
79  
80    /**
81     * Get the object that will be used to resolve URIs in href
82     * in xml-stylesheet processing instruction.
83     *
84     * @return The URIResolver that was set with setURIResolver.
85     */
86    public URIResolver getURIResolver()
87    {
88      return m_uriResolver;
89    }
90  
91    /**
92     * Construct a StylesheetPIHandler instance that will search
93     * for xml-stylesheet PIs based on the given criteria.
94     *
95     * @param baseID The base ID of the XML document, needed to resolve
96     *               relative IDs.
97     * @param media The desired media criteria.
98     * @param title The desired title criteria.
99     * @param charset The desired character set criteria.
100    */
101   public StylesheetPIHandler(String baseID, String media, String title,
102                              String charset)
103   {
104 
105     m_baseID = baseID;
106     m_media = media;
107     m_title = title;
108     m_charset = charset;
109   }
110 
111   /**
112    * Return the last stylesheet found that match the constraints.
113    *
114    * @return Source object that references the last stylesheet reference
115    *         that matches the constraints.
116    */
117   public Source getAssociatedStylesheet()
118   {
119 
120     int sz = m_stylesheets.size();
121 
122     if (sz > 0)
123     {
124       Source source = (Source) m_stylesheets.elementAt(sz-1);
125       return source;
126     }
127     else
128       return null;
129   }
130 
131   /**
132    * Handle the xml-stylesheet processing instruction.
133    *
134    * @param target The processing instruction target.
135    * @param data The processing instruction data, or null if
136    *             none is supplied.
137    * @throws org.xml.sax.SAXException Any SAX exception, possibly
138    *            wrapping another exception.
139    * @see org.xml.sax.ContentHandler#processingInstruction
140    * @see <a href="http://www.w3.org/TR/xml-stylesheet/">Associating Style Sheets with XML documents, Version 1.0</a>
141    */
142   public void processingInstruction(String target, String data)
143           throws org.xml.sax.SAXException
144   {
145 
146     if (target.equals("xml-stylesheet"))
147     {
148       String href = null;  // CDATA #REQUIRED
149       String type = null;  // CDATA #REQUIRED
150       String title = null;  // CDATA #IMPLIED
151       String media = null;  // CDATA #IMPLIED
152       String charset = null;  // CDATA #IMPLIED
153       boolean alternate = false;  // (yes|no) "no"
154       StringTokenizer tokenizer = new StringTokenizer(data, " \t=\n", true);
155       boolean lookedAhead = false;
156       Source source = null;
157 
158       String token = "";
159       while (tokenizer.hasMoreTokens())
160       {
161         if (!lookedAhead)
162           token = tokenizer.nextToken();
163         else
164           lookedAhead = false;
165         if (tokenizer.hasMoreTokens() &&
166                (token.equals(" ") || token.equals("\t") || token.equals("=")))
167           continue;
168 
169         String name = token;
170         if (name.equals("type"))
171         {
172           token = tokenizer.nextToken();
173           while (tokenizer.hasMoreTokens() &&
174                (token.equals(" " ) || token.equals("\t") || token.equals("=")))
175             token = tokenizer.nextToken();
176           type = token.substring(1, token.length() - 1);
177 
178         }
179         else if (name.equals("href"))
180         {
181           token = tokenizer.nextToken();
182           while (tokenizer.hasMoreTokens() &&
183                (token.equals(" " ) || token.equals("\t") || token.equals("=")))
184             token = tokenizer.nextToken();
185           href = token;
186           if (tokenizer.hasMoreTokens())
187           {
188             token = tokenizer.nextToken();
189             // If the href value has parameters to be passed to a
190             // servlet(something like "foobar?id=12..."),
191             // we want to make sure we get them added to
192             // the href value. Without this check, we would move on
193             // to try to process another attribute and that would be
194             // wrong.
195             // We need to set lookedAhead here to flag that we
196             // already have the next token.
197             while ( token.equals("=") && tokenizer.hasMoreTokens())
198             {
199               href = href + token + tokenizer.nextToken();
200               if (tokenizer.hasMoreTokens())
201               {
202                 token = tokenizer.nextToken();
203                 lookedAhead = true;
204               }
205               else
206               {
207                 break;
208               }
209             }
210           }
211           href = href.substring(1, href.length() - 1);
212           try
213           {
214             // Add code to use a URIResolver. Patch from Dmitri Ilyin.
215             if (m_uriResolver != null)
216             {
217               source = m_uriResolver.resolve(href, m_baseID);
218             }
219            else
220             {
221               href = SystemIDResolver.getAbsoluteURI(href, m_baseID);
222               source = new SAXSource(new InputSource(href));
223             }
224           }
225           catch(TransformerException te)
226           {
227             throw new org.xml.sax.SAXException(te);
228           }
229         }
230         else if (name.equals("title"))
231         {
232           token = tokenizer.nextToken();
233           while (tokenizer.hasMoreTokens() &&
234                (token.equals(" " ) || token.equals("\t") || token.equals("=")))
235             token = tokenizer.nextToken();
236           title = token.substring(1, token.length() - 1);
237         }
238         else if (name.equals("media"))
239         {
240           token = tokenizer.nextToken();
241           while (tokenizer.hasMoreTokens() &&
242                (token.equals(" " ) || token.equals("\t") || token.equals("=")))
243             token = tokenizer.nextToken();
244           media = token.substring(1, token.length() - 1);
245         }
246         else if (name.equals("charset"))
247         {
248           token = tokenizer.nextToken();
249           while (tokenizer.hasMoreTokens() &&
250               (token.equals(" " ) || token.equals("\t") || token.equals("=")))
251             token = tokenizer.nextToken();
252           charset = token.substring(1, token.length() - 1);
253         }
254         else if (name.equals("alternate"))
255         {
256           token = tokenizer.nextToken();
257           while (tokenizer.hasMoreTokens() &&
258                (token.equals(" " ) || token.equals("\t") || token.equals("=")))
259             token = tokenizer.nextToken();
260           alternate = token.substring(1, token.length()
261                                              - 1).equals("yes");
262         }
263 
264       }
265 
266       if ((null != type)
267           && (type.equals("text/xsl") || type.equals("text/xml") || type.equals("application/xml+xslt"))
268           && (null != href))
269       {
270         if (null != m_media)
271         {
272           if (null != media)
273           {
274             if (!media.equals(m_media))
275               return;
276           }
277           else
278             return;
279         }
280 
281         if (null != m_charset)
282         {
283           if (null != charset)
284           {
285             if (!charset.equals(m_charset))
286               return;
287           }
288           else
289             return;
290         }
291 
292         if (null != m_title)
293         {
294           if (null != title)
295           {
296             if (!title.equals(m_title))
297               return;
298           }
299           else
300             return;
301         }
302 
303         m_stylesheets.addElement(source);
304       }
305     }
306   }
307 
308 
309   /**
310    * The spec notes that "The xml-stylesheet processing instruction is allowed only in the prolog of an XML document.",
311    * so, at least for right now, I'm going to go ahead an throw a TransformerException
312    * in order to stop the parse.
313    *
314    * @param namespaceURI The Namespace URI, or an empty string.
315    * @param localName The local name (without prefix), or empty string if not namespace processing.
316    * @param qName The qualified name (with prefix).
317    * @param atts  The specified or defaulted attributes.
318    *
319    * @throws StopParseException since there can be no valid xml-stylesheet processing
320    *                            instructions past the first element.
321    */
322   public void startElement(
323           String namespaceURI, String localName, String qName, Attributes atts)
324             throws org.xml.sax.SAXException
325   {
326     throw new StopParseException();
327   }
328 
329   /**
330     * Added additional getter and setter methods for the Base Id
331     * to fix bugzilla bug 24187
332     *
333     */
334    public void setBaseId(String baseId) {
335        m_baseID = baseId;
336 
337    }
338    public String  getBaseId() {
339        return m_baseID ;
340    }
341 
342 }