View Javadoc
1   /*
2    * Copyright (c) 2002-2017 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package com.gargoylesoftware.htmlunit.xml;
16  
17  import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_XML;
18  import static java.nio.charset.StandardCharsets.UTF_8;
19  
20  import java.io.IOException;
21  import java.nio.charset.Charset;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.xml.parsers.ParserConfigurationException;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.w3c.dom.Attr;
31  import org.w3c.dom.DOMConfiguration;
32  import org.w3c.dom.DOMImplementation;
33  import org.w3c.dom.Document;
34  import org.w3c.dom.DocumentType;
35  import org.w3c.dom.Element;
36  import org.w3c.dom.EntityReference;
37  import org.w3c.dom.Node;
38  import org.xml.sax.SAXException;
39  
40  import com.gargoylesoftware.htmlunit.SgmlPage;
41  import com.gargoylesoftware.htmlunit.WebResponse;
42  import com.gargoylesoftware.htmlunit.WebWindow;
43  import com.gargoylesoftware.htmlunit.html.DomAttr;
44  import com.gargoylesoftware.htmlunit.html.DomElement;
45  import com.gargoylesoftware.htmlunit.html.DomProcessingInstruction;
46  
47  /**
48   * A page that will be returned for response with content type "text/xml".
49   *
50   * @author Marc Guillemot
51   * @author David K. Taylor
52   * @author Ahmed Ashour
53   * @author Frank Danek
54   */
55  public class XmlPage extends SgmlPage {
56  
57      private static final Log LOG = LogFactory.getLog(XmlPage.class);
58  
59      private Node node_;
60  
61      /**
62       * Creates an instance.
63       * A warning is logged if an exception is thrown while parsing the XML content
64       * (for instance when the content is not a valid XML and can't be parsed).
65       *
66       * @param webResponse the response from the server
67       * @param enclosingWindow the window that holds the page
68       * @throws IOException if the page could not be created
69       */
70      public XmlPage(final WebResponse webResponse, final WebWindow enclosingWindow) throws IOException {
71          this(webResponse, enclosingWindow, true);
72      }
73  
74      /**
75       * Creates an instance.
76       * A warning is logged if an exception is thrown while parsing the XML content
77       * (for instance when the content is not a valid XML and can't be parsed).
78       *
79       * @param node the node to initialize this page with
80       * @param enclosingWindow the window that holds the page
81       */
82      public XmlPage(final Node node, final WebWindow enclosingWindow) {
83          super(null, enclosingWindow);
84          node_ = node;
85          if (node_ != null) {
86              XmlUtil.appendChild(this, this, node_, true);
87          }
88      }
89  
90      /**
91       * Creates an instance.
92       * A warning is logged if an exception is thrown while parsing the XML content
93       * (for instance when the content is not a valid XML and can't be parsed).
94       *
95       * @param webResponse the response from the server
96       * @param enclosingWindow the window that holds the page
97       * @param ignoreSAXException Whether to ignore {@link SAXException} or throw it as {@link IOException}
98       * @throws IOException if the page could not be created
99       */
100     public XmlPage(final WebResponse webResponse, final WebWindow enclosingWindow, final boolean ignoreSAXException)
101         throws IOException {
102         this(webResponse, enclosingWindow, ignoreSAXException, true);
103     }
104 
105     /**
106      * Creates an instance.
107      * A warning is logged if an exception is thrown while parsing the XML content
108      * (for instance when the content is not a valid XML and can't be parsed).
109      *
110      * @param webResponse the response from the server
111      * @param enclosingWindow the window that holds the page
112      * @param ignoreSAXException Whether to ignore {@link SAXException} or throw it as {@link IOException}
113      * @param handleXHTMLAsHTML if true elements from the XHTML namespace are handled as HTML elements instead of
114      *     DOM elements
115      * @throws IOException if the page could not be created
116      */
117     public XmlPage(final WebResponse webResponse, final WebWindow enclosingWindow, final boolean ignoreSAXException,
118         final boolean handleXHTMLAsHTML) throws IOException {
119         super(webResponse, enclosingWindow);
120 
121         try {
122             try {
123                 final Document document = XmlUtil.buildDocument(webResponse);
124                 node_ = document.getFirstChild();
125             }
126             catch (final SAXException e) {
127                 LOG.warn("Failed parsing XML document " + webResponse.getWebRequest().getUrl()
128                         + ": " + e.getMessage());
129                 if (!ignoreSAXException) {
130                     throw new IOException(e.getMessage());
131                 }
132             }
133         }
134         catch (final ParserConfigurationException e) {
135             if (null == webResponse) {
136                 LOG.warn("Failed parsing XML empty document: " + e.getMessage());
137             }
138             else {
139                 LOG.warn("Failed parsing XML empty document " + webResponse.getWebRequest().getUrl()
140                     + ": " + e.getMessage());
141             }
142         }
143 
144         final Map<Integer, List<String>> attributesOrderMap;
145         if (node_ != null && getWebClient().getBrowserVersion().hasFeature(JS_XML)) {
146             attributesOrderMap = XmlUtil.getAttributesOrderMap(node_.getOwnerDocument());
147         }
148         else {
149             attributesOrderMap = null;
150         }
151         for (Node node = node_; node != null; node = node.getNextSibling()) {
152             XmlUtil.appendChild(this, this, node, handleXHTMLAsHTML, attributesOrderMap);
153         }
154     }
155 
156     /**
157      * {@inheritDoc}
158      */
159     @Override
160     public boolean hasCaseSensitiveTagNames() {
161         return true;
162     }
163 
164     /**
165      * Returns the DOM representation of the XML content.
166      * @return {@code null} if the content couldn't be parsed
167      */
168     public Document getXmlDocument() {
169         if (node_ != null) {
170             return node_.getOwnerDocument();
171         }
172         return null;
173     }
174 
175     /**
176      * {@inheritDoc}
177      * Not yet implemented.
178      */
179     @Override
180     public Node adoptNode(final Node source) {
181         throw new UnsupportedOperationException("XmlPage.adoptNode is not yet implemented.");
182     }
183 
184     /**
185      * {@inheritDoc}
186      * Not yet implemented.
187      */
188     @Override
189     public Attr createAttributeNS(final String namespaceURI, final String qualifiedName) {
190         throw new UnsupportedOperationException("XmlPage.createAttributeNS is not yet implemented.");
191     }
192 
193     /**
194      * {@inheritDoc}
195      */
196     @Override
197     public DomElement createElement(final String tagName) {
198         return createElementNS(null, tagName);
199     }
200 
201     /**
202      * {@inheritDoc}
203      */
204     @Override
205     public DomElement createElementNS(final String namespaceURI, final String qualifiedName) {
206         return new DomElement(namespaceURI, qualifiedName, this, new HashMap<String, DomAttr>());
207     }
208 
209     /**
210      * {@inheritDoc}
211      * Not yet implemented.
212      */
213     @Override
214     public EntityReference createEntityReference(final String name) {
215         throw new UnsupportedOperationException("XmlPage.createEntityReference is not yet implemented.");
216     }
217 
218     /**
219      * {@inheritDoc}
220      */
221     @Override
222     public DomProcessingInstruction createProcessingInstruction(final String target, final String data) {
223         return new DomProcessingInstruction(this, target, data);
224     }
225 
226     /**
227      * {@inheritDoc}
228      * Not yet implemented.
229      */
230     @Override
231     public String getDocumentURI() {
232         throw new UnsupportedOperationException("XmlPage.getDocumentURI is not yet implemented.");
233     }
234 
235     /**
236      * {@inheritDoc}
237      * Not yet implemented.
238      */
239     @Override
240     public DOMConfiguration getDomConfig() {
241         throw new UnsupportedOperationException("XmlPage.getDomConfig is not yet implemented.");
242     }
243 
244     /**
245      * {@inheritDoc}
246      * Not yet implemented.
247      */
248     @Override
249     public Element getElementById(final String elementId) {
250         throw new UnsupportedOperationException("XmlPage.getElementById is not yet implemented.");
251     }
252 
253     /**
254      * {@inheritDoc}
255      * Not yet implemented.
256      */
257     @Override
258     public DOMImplementation getImplementation() {
259         throw new UnsupportedOperationException("XmlPage.getImplementation is not yet implemented.");
260     }
261 
262     /**
263      * {@inheritDoc}
264      * Not yet implemented.
265      */
266     @Override
267     public String getInputEncoding() {
268         throw new UnsupportedOperationException("XmlPage.getInputEncoding is not yet implemented.");
269     }
270 
271     /**
272      * {@inheritDoc}
273      * Not yet implemented.
274      */
275     @Override
276     public boolean getStrictErrorChecking() {
277         throw new UnsupportedOperationException("XmlPage.getStrictErrorChecking is not yet implemented.");
278     }
279 
280     /**
281      * {@inheritDoc}
282      */
283     @Override
284     public String getXmlEncoding() {
285         return null;
286     }
287 
288     /**
289      * {@inheritDoc}
290      */
291     @Override
292     public boolean getXmlStandalone() {
293         return false;
294     }
295 
296     /**
297      * {@inheritDoc}
298      */
299     @Override
300     public String getXmlVersion() {
301         return "1.0";
302     }
303 
304     /**
305      * {@inheritDoc}
306      * Not yet implemented.
307      */
308     @Override
309     public Node importNode(final Node importedNode, final boolean deep) {
310         throw new UnsupportedOperationException("XmlPage.importNode is not yet implemented.");
311     }
312 
313     /**
314      * {@inheritDoc}
315      * Not yet implemented.
316      */
317     @Override
318     public Node renameNode(final Node n, final String namespaceURI, final String qualifiedName) {
319         throw new UnsupportedOperationException("XmlPage.renameNode is not yet implemented.");
320     }
321 
322     /**
323      * {@inheritDoc}
324      * Not yet implemented.
325      */
326     @Override
327     public void setDocumentURI(final String documentURI) {
328         throw new UnsupportedOperationException("XmlPage.setDocumentURI is not yet implemented.");
329     }
330 
331     /**
332      * {@inheritDoc}
333      * Not yet implemented.
334      */
335     @Override
336     public void setStrictErrorChecking(final boolean strictErrorChecking) {
337         throw new UnsupportedOperationException("XmlPage.setStrictErrorChecking is not yet implemented.");
338     }
339 
340     /**
341      * {@inheritDoc}
342      * Not yet implemented.
343      */
344     @Override
345     public void setXmlStandalone(final boolean xmlStandalone) {
346         throw new UnsupportedOperationException("XmlPage.setXmlStandalone is not yet implemented.");
347     }
348 
349     /**
350      * {@inheritDoc}
351      * Not yet implemented.
352      */
353     @Override
354     public void setXmlVersion(final String xmlVersion) {
355         throw new UnsupportedOperationException("XmlPage.setXmlVersion is not yet implemented.");
356     }
357 
358     /**
359      * {@inheritDoc}
360      */
361     @Override
362     public Charset getCharset() {
363         return UTF_8;
364     }
365 
366     /**
367      * {@inheritDoc}
368      */
369     @Override
370     public String getContentType() {
371         return "application/xml";
372     }
373 
374     /**
375      * {@inheritDoc}
376      */
377     @Override
378     protected void setDocumentType(final DocumentType type) {
379         super.setDocumentType(type);
380     }
381 }