2014-06-05 15 views
5

Ich benutze jsoup 1.7.3 mit Whitelist benutzerdefinierte Konfiguration.Jsoup WhiteList, um Kommentare zuzulassen

Anscheinend saniert es alle HTML-Kommentare (<!-- ... -->) innerhalb des Dokuments.

Es desinfiziert auch das Element <!DOCTYPE ...>.

  1. Wie kann ich jsoup Whitelist Kommentare wie zu ermöglichen?
  2. Wie kann ich das !DOCTYPE Element als zulässiges Element mit einem Attribut definieren?

Antwort

3

Dies ist nicht möglich mit Standard-JSoup-Klassen und nicht von WhiteList abhängig. Es ist die org.jsoup.safety.Cleaner. Der Cleaner verwendet einen Node-Traverser, der nur Elemente und Textknoten zulässt. Auch wird nur der Körper geparst. Also werden Kopf und Doctype komplett ignoriert. Um dies zu erreichen, müssen Sie einen benutzerdefinierten Reiniger erstellen. Zum Beispiel, wenn Sie einen html wie

haben

Sie werden zuerst einen benutzerdefinierten Reiniger erstellen, der den ursprünglichen kopiert. Bitte beachten Sie jedoch das Paket sollte org.jsoup.safety als der Reiniger verwendet einige der geschützten Methode der Whitelist zugeordnet. Außerdem ist es nicht sinnvoll, den Cleaner zu erweitern, da fast alle Methoden privat sind und der interne Knoten-Transquerer endgültig ist.

package org.jsoup.safety; 

import org.jsoup.helper.Validate; 
import org.jsoup.nodes.Attribute; 
import org.jsoup.nodes.Attributes; 
import org.jsoup.nodes.Comment; 
import org.jsoup.nodes.DataNode; 
import org.jsoup.nodes.Document; 
import org.jsoup.nodes.DocumentType; 
import org.jsoup.nodes.Element; 
import org.jsoup.nodes.Node; 
import org.jsoup.nodes.TextNode; 
import org.jsoup.parser.Tag; 
import org.jsoup.select.NodeTraversor; 
import org.jsoup.select.NodeVisitor; 

public class CustomCleaner { 
    private Whitelist whitelist; 

    public CustomCleaner(Whitelist whitelist) { 
    Validate.notNull(whitelist); 
    this.whitelist = whitelist; 
    } 

    public Document clean(Document dirtyDocument) { 
    Validate.notNull(dirtyDocument); 

    Document clean = Document.createShell(dirtyDocument.baseUri()); 
    copyDocType(dirtyDocument, clean); 
    if (dirtyDocument.head() != null) 
     copySafeNodes(dirtyDocument.head(), clean.head()); 
    if (dirtyDocument.body() != null) // frameset documents won't have a body. the clean doc will have empty body. 
     copySafeNodes(dirtyDocument.body(), clean.body()); 

    return clean; 
    } 

    private void copyDocType(Document dirtyDocument, Document clean) { 
    dirtyDocument.traverse(new NodeVisitor() { 
     public void head(Node node, int depth) { 
     if (node instanceof DocumentType) { 
      clean.prependChild(node); 
     } 
     } 
     public void tail(Node node, int depth) { } 
    }); 
    } 

    public boolean isValid(Document dirtyDocument) { 
    Validate.notNull(dirtyDocument); 

    Document clean = Document.createShell(dirtyDocument.baseUri()); 
    int numDiscarded = copySafeNodes(dirtyDocument.body(), clean.body()); 
    return numDiscarded == 0; 
    } 

    private final class CleaningVisitor implements NodeVisitor { 
    private int numDiscarded = 0; 
    private final Element root; 
    private Element destination; // current element to append nodes to 

    private CleaningVisitor(Element root, Element destination) { 
     this.root = root; 
     this.destination = destination; 
    } 

    public void head(Node source, int depth) { 
     if (source instanceof Element) { 
     Element sourceEl = (Element) source; 

     if (whitelist.isSafeTag(sourceEl.tagName())) { // safe, clone and copy safe attrs 
      ElementMeta meta = createSafeElement(sourceEl); 
      Element destChild = meta.el; 
      destination.appendChild(destChild); 

      numDiscarded += meta.numAttribsDiscarded; 
      destination = destChild; 
     } else if (source != root) { // not a safe tag, so don't add. don't count root against discarded. 
      numDiscarded++; 
     } 
     } else if (source instanceof TextNode) { 
     TextNode sourceText = (TextNode) source; 
     TextNode destText = new TextNode(sourceText.getWholeText(), source.baseUri()); 
     destination.appendChild(destText); 
     } else if (source instanceof Comment) { 
     Comment sourceComment = (Comment) source; 
     Comment destComment = new Comment(sourceComment.getData(), source.baseUri()); 
     destination.appendChild(destComment); 
     } else if (source instanceof DataNode) { 
     DataNode sourceData = (DataNode) source; 
     DataNode destData = new DataNode(sourceData.getWholeData(), source.baseUri()); 
     destination.appendChild(destData); 
     } else { // else, we don't care about comments, xml proc instructions, etc 
     numDiscarded++; 
     } 
    } 

    public void tail(Node source, int depth) { 
     if (source instanceof Element && whitelist.isSafeTag(source.nodeName())) { 
     destination = destination.parent(); // would have descended, so pop destination stack 
     } 
    } 
    } 

    private int copySafeNodes(Element source, Element dest) { 
    CleaningVisitor cleaningVisitor = new CleaningVisitor(source, dest); 
    NodeTraversor traversor = new NodeTraversor(cleaningVisitor); 
    traversor.traverse(source); 
    return cleaningVisitor.numDiscarded; 
    } 

    private ElementMeta createSafeElement(Element sourceEl) { 
    String sourceTag = sourceEl.tagName(); 
    Attributes destAttrs = new Attributes(); 
    Element dest = new Element(Tag.valueOf(sourceTag), sourceEl.baseUri(), destAttrs); 
    int numDiscarded = 0; 

    Attributes sourceAttrs = sourceEl.attributes(); 
    for (Attribute sourceAttr : sourceAttrs) { 
     if (whitelist.isSafeAttribute(sourceTag, sourceEl, sourceAttr)) 
     destAttrs.put(sourceAttr); 
     else 
     numDiscarded++; 
    } 
    Attributes enforcedAttrs = whitelist.getEnforcedAttributes(sourceTag); 
    destAttrs.addAll(enforcedAttrs); 

    return new ElementMeta(dest, numDiscarded); 
    } 

    private static class ElementMeta { 
    Element el; 
    int numAttribsDiscarded; 

    ElementMeta(Element el, int numAttribsDiscarded) { 
     this.el = el; 
     this.numAttribsDiscarded = numAttribsDiscarded; 
    } 
    } 

} 

Sobald Sie beide haben, können Sie wie gewohnt reinigen. Wie

import java.io.File; 
import java.io.IOException; 

import org.jsoup.Jsoup; 
import org.jsoup.nodes.Document; 
import org.jsoup.safety.CustomCleaner; 
import org.jsoup.safety.Whitelist; 

public class CustomJsoupSanitizer { 

    public static void main(String[] args) { 
     try { 
      Document doc = Jsoup.parse(new File("t2.html"), "UTF-8"); 
      CustomCleaner cleaner = new CustomCleaner(Whitelist.relaxed().addTags("script")); 
      Document doc2 = cleaner.clean(doc); 
      System.out.println(doc2.html()); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

    } 

} 

Dies gibt Ihnen die hygienisiert Ausgang für über html als

<!DOCTYPE html> 
<html> 
<head> 
    <!-- This is a script --> 
    <script> 
     function newFun() { 
      alert(1); 
     } 
    </script> 
</head> 
<body>  
    <!-- This is another comment. --> 
    <div> 
    Test 
    </div> 
</body> 
</html> 

Sie den Reiniger Ihre Anforderung entsprechen anpassen können. d. h. Kopfknoten oder Skript-Tag usw. zu vermeiden ...

+0

Das, was ich hatte Angst vor. Vielen Dank. Ich wünschte, die Art der zu analysierenden Elemente wäre auch konfigurierbar. – Genry

0

Die Jsoup Cleaner nicht geben Ihnen eine Chance, hier (l 100.):

} else { // else, we don't care about comments, xml proc instructions, etc 
    numDiscarded++; 
} 

Nur Instanzen Element und TextNode können in den gereinigten HTML bleiben.

Ihre einzige Chance kann etwas schreckliches sein, wie das Parsen des Dokuments, das Ersetzen der Kommentare und des Doctypes durch ein spezielles Whitelist-Tag, das Säubern des Dokuments und das anschließende Parsen und Ersetzen der speziellen Tags.

Verwandte Themen