2014-06-05 8 views
5

Whitelist 사용자 설정으로 jsoup 1.7.3을 사용하고 있습니다.Jsoup 의견을 허용하는 화이트리스트

분명히 문서 내의 모든 HTML 주석 (<!-- ... -->)이 삭제됩니다.

또한 <!DOCTYPE ...> 요소를 살균합니다.

  1. 코멘트를 그대로 사용하려면 jsoup Whitelist을 어떻게받을 수 있습니까?
  2. 어떤 속성으로 허용 요소로 !DOCTYPE 요소를 어떻게 정의 할 수 있습니까?

답변

3

이것은 표준 JSoup 클래스 및 WhiteList에 종속되지 않음에 의해 불가능합니다. 그것의 org.jsoup.safety.Cleaner. 클리너는 요소와 텍스트 노드 만 허용하는 노드 통과자를 사용합니다. 또한 본문 만 구문 분석됩니다. 따라서 머리와 doctype은 완전히 무시됩니다. 따라서이를 달성하려면 사용자 지정 청소기를 만들어야합니다. 예를 들어 html로 작성한 경우

<!DOCTYPE html> 
<html> 
    <head> 
    <!-- This is a script --> 
    <script type="text/javascript"> 
     function newFun() { 
      alert(1); 
     } 
    </script> 
    </head> 
    <body> 
     <map name="diagram_map"> 
      <area id="area1" /> 
      <area id="area2" /> 
     </map> 
     <!-- This is another comment. --> 
     <div>Test</div> 
    </body> 
</html> 

원래 사용자 정의 클리너를 작성하여 원본을 복사합니다. 그러나 패키지는 org.jsoup.safety이어야합니다. 따라서 클리너는 허용 된 화이트리스트의 보호 된 방법 중 일부를 사용합니다. 또한 거의 모든 메소드가 private이고 내부 노드 traverser가 final이기 때문에 Cleaner를 확장하는 것은 중요하지 않습니다.

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; 
    } 
    } 

} 

일단 정상적으로 청소를 할 수 있습니다.

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(); 
     } 

    } 

} 

처럼 이것은 당신이 귀하의 요구 사항에 맞게 청소기를 사용자 정의 할 수 있습니다

<!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> 

당신에게 위의 HTML에 대한 소독 출력을 제공 할 것입니다. 머리 노드 또는 스크립트 태그 등을 피하십시오.

+0

내가 두려워했던 것. 감사. 나는 '분석 할 요소의 유형'도 구성 가능하다. – Genry

0

Jsoup Cleaner은 (L 100). 여기에 당신에게 기회를주지 않습니다 정화 된 HTML에 남아있을 수 ElementTextNode

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

만 인스턴스.

문서를 구문 분석하고 주석과 doctype을 특수 허용 된 태그로 바꾸고, 문서를 정리 한 다음 특수 태그를 다시 구문 분석하고 바꾸는 것만 끔찍할 수 있습니다.