Mit JTidy erstelltes Dokument mit XPath auslesen

newbeet

Grünschnabel
Hallo,

seit geraumer Zeit habe ich das Problem, ein Dokument dass ich mit JTidy erstellt habe, mit XPath auszulesen.

Ich habe eine einfache Java-Klasse mit den entsprechenden Funktionalitäten erstellt:

Code:
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.NodeList;
import org.w3c.tidy.Tidy;


public class Main {

  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    org.w3c.dom.Document document = null; 
    
    Tidy tidy = new Tidy();
    XPath xpath = XPathFactory.newInstance().newXPath();
    
    
    tidy.setHideComments(true);
    tidy.setInputEncoding("UTF-8");
    tidy.setOutputEncoding("UTF-8");
    tidy.setTidyMark(false);

    tidy.setQuiet(true);
    tidy.setShowErrors(0);
    tidy.setShowWarnings(false);

    try {
      document = tidy.parseDOM(new URL(args[0]).openStream(), null);
      tidy.pprint(document, System.out);
      
      XPathExpression expr = xpath.compile("//title");
      Object result = expr.evaluate(document,
            XPathConstants.NODESET);
      
      NodeList nodes = (NodeList) result;    
      System.out.println(nodes.getLength());
      
      /** _------------- CATCHES -----------*/
    } catch (MalformedURLException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

    } catch (XPathExpressionException e) {
    // TODO Auto-generated catch block
      e.printStackTrace();
  }
  }
}

Über die Kommandozeile kann also eine Webseite angegeben werden, z.b. http://www.bild.de (oder was auch immer).
Das funktioniert eigentlich auch (fast) immer. Nicht funktionieren tut es z.B. bei http://www.fh-wedel.de
Und ich frage mich verzweifelt: WIESOOOO?

Frage ich diese url ab, erhalte ich in folgender Zeile eine Exception:
Code:
Object result = expr.evaluate(document,
            XPathConstants.NODESET);

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at com.sun.org.apache.xml.internal.dtm.ref.ExpandedNameTable.getType(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase.indexNode(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM.addNode(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM.nextNode(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase._firstch(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBaseTraversers$DescendantFromRootTraverser.getFirstPotential(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBaseTraversers$DescendantFromRootTraverser.first(Unknown Source)
at com.sun.org.apache.xpath.internal.axes.DescendantIterator.nextNode(Unknown Source)
at com.sun.org.apache.xpath.internal.axes.NodeSequence.nextNode(Unknown Source)
at com.sun.org.apache.xpath.internal.axes.NodeSequence.runTo(Unknown Source)
at com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList.<init>(Unknown Source)
at com.sun.org.apache.xpath.internal.objects.XNodeSet.nodelist(Unknown Source)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.getResultAsType(Unknown Source)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.eval(Unknown Source)
at com.sun.org.apache.xpath.internal.jaxp.XPathExpressionImpl.evaluate(Unknown Source)
at Main.main(Main.java:42)

Hat irgendwer vielleicht eine Idee woran das liegen könnte, bzw. was man dagegen tun kann

Ich bin wirklich ratlos...

Danke!
 
Hallo,

der XPathExpression Evaluator hat wohl Probleme mit dem HTML... fehlerhafte Elemente?
Vielleicht fehlt bei der Konfiguration von JTidy noch eine Einstellung.

Aber hier mal ein Workaround... mit JTidy das HTML aufgeräumt (pprint) in einen Buffer ausgeben lassen und aus diesem Buffer wieder ein neues XML Document aufbauen lassen. Damit lassen sich dann die XPath Ausdrücke auswerten.

Java:
package de.tutorials.training;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.tidy.Tidy;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {

        Tidy tidy = new Tidy();

        tidy.setHideComments(true);
        tidy.setInputEncoding("UTF-8");
        tidy.setOutputEncoding("UTF-8");
        tidy.setTidyMark(false);

        tidy.setQuiet(true);
        tidy.setShowErrors(0);
        tidy.setShowWarnings(false);

        String url = args[0];
        Document document = tidy.parseDOM(new URL(url).openStream(), null);
        tidy.pprint(document, System.out);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        tidy.pprint(document, baos);

        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
                .newInstance();
        docBuilderFactory
                .setFeature(
                        "http://apache.org/xml/features/nonvalidating/load-external-dtd",
                        false);

        document = docBuilderFactory.newDocumentBuilder().parse(
                new ByteArrayInputStream(baos.toByteArray()));

        XPathFactory xpathFactory = XPathFactory.newInstance();
        XPath xpath = xpathFactory.newXPath();

        XPathExpression expr = xpath.compile("//title");
        Object result = expr.evaluate(document, XPathConstants.NODESET);

        NodeList nodes = (NodeList) result;
        System.out.println(nodes.getLength());

        for (int i = 0, n = nodes.getLength(); i < n; i++) {
            Node node = nodes.item(i);
            System.out.println(node.getTextContent());
        }
    }
}

Gruß Tom
 
Zurück