View Javadoc
1   /* 
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    * http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   *
14   */
15  
16  package org.esigate.xml;
17  
18  import java.io.IOException;
19  import java.io.StringReader;
20  import java.io.Writer;
21  
22  import javax.xml.xpath.XPath;
23  import javax.xml.xpath.XPathConstants;
24  import javax.xml.xpath.XPathExpression;
25  import javax.xml.xpath.XPathExpressionException;
26  import javax.xml.xpath.XPathFactory;
27  
28  import nu.validator.htmlparser.common.DoctypeExpectation;
29  import nu.validator.htmlparser.dom.Dom2Sax;
30  import nu.validator.htmlparser.dom.HtmlDocumentBuilder;
31  
32  import org.esigate.Renderer;
33  import org.esigate.impl.DriverRequest;
34  import org.w3c.dom.Document;
35  import org.w3c.dom.NodeList;
36  import org.xml.sax.InputSource;
37  import org.xml.sax.SAXException;
38  
39  /**
40   * XML renderer.
41   * <p>
42   * Applies optional XPath evaluation and XSLT transformation to the retrieved data.
43   * 
44   * @author Stanislav Bernatskyi
45   */
46  public class XpathRenderer implements Renderer {
47      private static final HtmlNamespaceContext HTML_NAMESPACE_CONTEXT = new HtmlNamespaceContext();
48      private static final XPathFactory X_PATH_FACTORY = XPathFactory.newInstance();
49      private final XPathExpression expr;
50  
51      public XpathRenderer(String xpath) {
52          try {
53              XPath xpathObj = X_PATH_FACTORY.newXPath();
54              xpathObj.setNamespaceContext(HTML_NAMESPACE_CONTEXT);
55              this.expr = xpathObj.compile(xpath);
56          } catch (XPathExpressionException e) {
57              throw new ProcessingFailedException("failed to compile XPath expression", e);
58          }
59      }
60  
61      /** {@inheritDoc} */
62      @Override
63      public void render(DriverRequest httpRequest, String src, Writer out) throws IOException {
64          try {
65              HtmlDocumentBuilder htmlDocumentBuilder = new HtmlDocumentBuilder();
66              htmlDocumentBuilder.setDoctypeExpectation(DoctypeExpectation.NO_DOCTYPE_ERRORS);
67              Document document = htmlDocumentBuilder.parse(new InputSource(new StringReader(src)));
68              NodeList matchingNodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
69              XhtmlSerializer serializer = new XhtmlSerializer(out);
70              Dom2Sax dom2Sax = new Dom2Sax(serializer, serializer);
71              for (int i = 0; i < matchingNodes.getLength(); i++) {
72                  dom2Sax.parse(matchingNodes.item(i));
73              }
74          } catch (XPathExpressionException e) {
75              throw new ProcessingFailedException("Failed to evaluate XPath expression", e);
76          } catch (SAXException e) {
77              throw new ProcessingFailedException("Unable to parse source", e);
78          }
79      }
80  }