2016-03-26 9 views
4

_, das ist meine Webseite:Wie generiert man eine XPath-Abfrage, die zu einem bestimmten Element in Jsoup passt? Hallo

<html> 
    <head> 
    </head> 
    <body> 
     <div> text div 1</div> 
     <div> 
      <span>text of first span </span> 
      <span>text of second span </span> 
     </div> 
     <div> text div 3 </div> 
    </body> 
</html> 

Ich verwende jsoup es zu analysieren, und wechseln Sie dann alle Elemente innerhalb der Seite und erhalten ihre Wege:

Document doc = Jsoup.parse(new File("C:\\Users\\HC\\Desktop\\dataset\\index.html"), "UTF-8"); 
Elements elements = doc.body().select("*"); 
ArrayList all = new ArrayList(); 
     for (Element element : elements) { 
      if (!element.ownText().isEmpty()) { 

       StringBuilder path = new StringBuilder(element.nodeName()); 
       String value = element.ownText(); 
       Elements p_el = element.parents(); 

       for (Element el : p_el) { 
        path.insert(0, el.nodeName() + '/'); 
       } 
       all.add(path + " = " + value + "\n"); 
       System.out.println(path +" = "+ value); 
      } 
     } 

     return all; 

meinen Code geben ich dieses Ergebnis:

html/body/div = text div 1 
html/body/div/span = text of first span 
html/body/div/span = text of second span 
html/body/div = text div 3 

in der Tat mag ich wie folgt Ergebnis:

html/body/div[1] = text div 1 
html/body/div[2]/span[1] = text of first span 
html/body/div[2]/span[2] = text of second span 
html/body/div[3] = text div 3 

bitte könnte mir jemand eine Idee geben, wie man dieses Ergebnis erreicht :). Danke im Voraus.

Antwort

2

Wie hier eine Idee gefragt. Auch wenn ich mir ziemlich sicher bin, dass es bessere Lösungen gibt, um den XPath für einen bestimmten Knoten zu bekommen. Verwenden Sie zum Beispiel xslt wie in der answer, um "Xpath aus XML-Knoten Java generieren/erhalten".

Hier die mögliche Lösung basierend auf Ihrem aktuellen Versuch.

Überprüfen Sie für jedes (übergeordnete) Element, ob mehrere Elemente mit diesem Namen vorhanden sind. Pseudo-Code: if (count (el.select('../' + el.nodeName()) > 1)
Wenn wahre zählen die preceding-sibling:: mit dem Namen derselben und 1.
count (el.select('preceding-sibling::' + el.nodeName()) +1

+0

ja es logische Analyse ist, ich werde versuchen, Dank :) – kivok94

0
hinzufügen

Dies wäre einfacher, wenn Sie das Dokument von der Wurzel zu den Blättern statt umgekehrt verfahren. Auf diese Weise können Sie die Elemente einfach nach Tag-Name gruppieren und mehrere Ereignisse entsprechend behandeln. Hier ist ein rekursive Ansatz:

private final List<String> path = new ArrayList<>(); 
private final List<String> all = new ArrayList<>(); 

public List<String> getAll() { 
    return Collections.unmodifiableList(all); 
} 

public void parse(Document doc) { 
    path.clear(); 
    all.clear(); 
    parse(doc.children()); 
} 

private void parse(List<Element> elements) { 
    if (elements.isEmpty()) { 
     return; 
    } 
    Map<String, List<Element>> grouped = elements.stream().collect(Collectors.groupingBy(Element::tagName)); 

    for (Map.Entry<String, List<Element>> entry : grouped.entrySet()) { 
     List<Element> list = entry.getValue(); 
     String key = entry.getKey(); 
     if (list.size() > 1) { 
      int index = 1; 
      // use paths with index 
      key += "["; 
      for (Element e : list) { 
       path.add(key + (index++) + "]"); 
       handleElement(e); 
       path.remove(path.size() - 1); 
      } 
     } else { 
      // use paths without index 
      path.add(key); 
      handleElement(list.get(0)); 
      path.remove(path.size() - 1); 
     } 
    } 

} 

private void handleElement(Element e) { 
    String value = e.ownText(); 
    if (!value.isEmpty()) { 
     // add entry 
     all.add(path.stream().collect(Collectors.joining("/")) + " = " + value); 
    } 
    // process children of element 
    parse(e.children()); 
} 
+0

ur Antwort ist in der Nähe von dem, was ich will, Ich werde nur einige Änderungen vorgenommen und es wird perfekt funktionieren, denn jetzt gibt es so ein Ergebnis – kivok94

+0

div [1] = Text div 1 div [2]/span [1] = Text der ersten Spanne div [2]/span [2] = Text der zweiten Spanne div [3] = Text div 2 Körper/div [1] = Text div 1 Körper/div [2]/span [1] = Text der ersten Spanne body/div [2]/span [2] = Text der zweiten Spanne body/div [3] = Text div 2 span [1] = Text der ersten Spanne span [2] = Text der zweiten Spanne – kivok94

1

Dies ist meine Lösung für dieses Problem:

StringBuilder absPath=new StringBuilder(); 
Elements parents = htmlElement.parents(); 

for (int j = parents.size()-1; j >= 0; j--) { 
    Element element = parents.get(j); 
    absPath.append("/"); 
    absPath.append(element.tagName()); 
    absPath.append("["); 
    absPath.append(element.siblingIndex()); 
    absPath.append("]"); 
} 
+0

Scheint gut für mich :) –

Verwandte Themen