Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 解析格式错误的XML文档(如HTML文件)_Java_Html_Xml_Xml Parsing - Fatal编程技术网

Java 解析格式错误的XML文档(如HTML文件)

Java 解析格式错误的XML文档(如HTML文件),java,html,xml,xml-parsing,Java,Html,Xml,Xml Parsing,在解析之后,我想删除危险的代码,并以正确的格式再次写出它 其目的是防止脚本通过电子邮件进入,但仍然允许大量糟糕的HTML正常工作(至少不会完全失败) 有图书馆吗?有没有更好的方法让脚本远离浏览器 重要的是程序不会抛出解析异常。程序可能会做出最好的猜测,即使它是错误的,也是可以接受的 编辑:我非常感谢大家对哪些解析器更好以及为什么更好的评论。使用一种可用的工具将HTML转换为XHTML 比如说 等 然后使用常规XML解析器。进行灵活的解析。但白名单才是解决问题的办法。如果您只是不允许一堆“危

在解析之后,我想删除危险的代码,并以正确的格式再次写出它

其目的是防止脚本通过电子邮件进入,但仍然允许大量糟糕的HTML正常工作(至少不会完全失败)

有图书馆吗?有没有更好的方法让脚本远离浏览器

重要的是程序不会抛出解析异常。程序可能会做出最好的猜测,即使它是错误的,也是可以接受的


编辑:我非常感谢大家对哪些解析器更好以及为什么更好的评论。

使用一种可用的工具将HTML转换为XHTML

比如说


然后使用常规XML解析器。

进行灵活的解析。但白名单才是解决问题的办法。如果您只是不允许一堆“危险”的元素,那么可能有人会找到一种方法,通过您的解析器来隐藏某些内容。相反,您应该只允许一小部分安全元素。

为此,我使用

对他们的消毒剂示例进行了一些调整:

public class HtmlSanitizer {

private HtmlSanitizer() {
}

private static final Set<String> VALID_ELEMENTS = Sets.newHashSet(DIV, BR,
        P, B, I, OL, UL, LI, A, STRONG, SPAN, EM, TT, IMG);


private static final Set<String> VALID_ATTRIBUTES = Sets.newHashSet("id",
        "class", "href", "target", "title", "src");

private static final Object VALID_MARKER = new Object();

public static void sanitize(Reader r, Writer w) {
    try {
        sanitize(new Source(r)).writeTo(w);
        w.flush();
        r.close();
    } catch (IOException ioe) {
        throw new RuntimeException("error during sanitize", ioe);
    }
}

public static OutputDocument sanitize(Source source) {
    source.fullSequentialParse();
    OutputDocument doc = new OutputDocument(source);
    List<Tag> tags = source.getAllTags();
    int pos = 0;
    for (Tag tag : tags) {
        if (processTag(tag, doc))
            tag.setUserData(VALID_MARKER);
        else
            doc.remove(tag);
        reencodeTextSegment(source, doc, pos, tag.getBegin());
        pos = tag.getEnd();
    }
    reencodeTextSegment(source, doc, pos, source.getEnd());
    return doc;
}

private static boolean processTag(Tag tag, OutputDocument doc) {
    String elementName = tag.getName();
    if (!VALID_ELEMENTS.contains(elementName))
        return false;
    if (tag.getTagType() == StartTagType.NORMAL) {
        Element element = tag.getElement();
        if (HTMLElements.getEndTagRequiredElementNames().contains(
                elementName)) {
            if (element.getEndTag() == null)
                return false;
        } else if (HTMLElements.getEndTagOptionalElementNames().contains(
                elementName)) {
            if (elementName == HTMLElementName.LI && !isValidLITag(tag))
                return false;
            if (element.getEndTag() == null)
                doc.insert(element.getEnd(), getEndTagHTML(elementName));

        }
        doc.replace(tag, getStartTagHTML(element.getStartTag()));
    } else if (tag.getTagType() == EndTagType.NORMAL) {
        if (tag.getElement() == null)
            return false;
        if (elementName == HTMLElementName.LI && !isValidLITag(tag))
            return false;
        doc.replace(tag, getEndTagHTML(elementName));
    } else {
        return false;
    }
    return true;
}

private static boolean isValidLITag(Tag tag) {
    Element parentElement = tag.getElement().getParentElement();
    if (parentElement == null
            || parentElement.getStartTag().getUserData() != VALID_MARKER)
        return false;
    return parentElement.getName() == HTMLElementName.UL
            || parentElement.getName() == HTMLElementName.OL;
}

private static void reencodeTextSegment(Source source, OutputDocument doc,
        int begin, int end) {
    if (begin >= end)
        return;
    Segment textSegment = new Segment(source, begin, end);
    String encodedText = encode(decode(textSegment));
    doc.replace(textSegment, encodedText);
}

private static CharSequence getStartTagHTML(StartTag startTag) {
    StringBuilder sb = new StringBuilder();
    sb.append('<').append(startTag.getName());
    for (Attribute attribute : startTag.getAttributes()) {
        if (VALID_ATTRIBUTES.contains(attribute.getKey())) {
            sb.append(' ').append(attribute.getName());
            if (attribute.getValue() != null) {
                sb.append("=\"");
                sb.append(CharacterReference.encode(attribute.getValue()));
                sb.append('"');
            }
        }
    }
    if (startTag.getElement().getEndTag() == null
            && !HTMLElements.getEndTagOptionalElementNames().contains(
                    startTag.getName()))
        sb.append('/');
    sb.append('>');
    return sb;
}

private static String getEndTagHTML(String tagName) {
    return "</" + tagName + '>';
}

}
公共类HtmlSanitizer{
私有HtmlSanitizer(){
}
私有静态最终集VALID_ELEMENTS=Sets.newHashSet(DIV,BR,
P、 B,I,OL,UL,LI,A,STRONG,SPAN,EM,TT,IMG);
private static final Set VALID_ATTRIBUTES=Sets.newHashSet(“id”,
“类”、“href”、“目标”、“标题”、“src”);
私有静态最终对象有效_标记=新对象();
公共静态无效清理(读卡器r、写卡器w){
试一试{
消毒(新来源(r))。写入(w);
w、 冲洗();
r、 close();
}捕获(ioe异常ioe){
抛出新的运行时异常(“清理期间出错”,ioe);
}
}
公共静态输出文档清理(源){
source.fullSequentialParse();
OutputDocument单据=新的OutputDocument(来源);
List tags=source.getAllTags();
int pos=0;
用于(标记:标记){
if(processTag(tag,doc))
tag.setUserData(有效的_标记);
其他的
文件移除(标签);
reencodeTextSegment(source、doc、pos、tag.getBegin());
pos=tag.getEnd();
}
reencodeTextSegment(source、doc、pos、source.getEnd());
退货单;
}
私有静态布尔processTag(Tag标签,OutputDocument文档){
String elementName=tag.getName();
如果(!VALID_ELEMENTS.contains(elementName))
返回false;
if(tag.getTagType()==StartTagType.NORMAL){
Element=tag.getElement();
如果(HTMLElements.getEndTagRequiredElementNames()包含(
元素名称){
if(element.getEndTag()==null)
返回false;
}else if(HTMLElements.getEndTagOptionalElementNames()包含(
元素名称){
if(elementName==HTMLElementName.LI&&!isValidLITag(标记))
返回false;
if(element.getEndTag()==null)
insert(element.getEnd(),getEndTagHTML(elementName));
}
doc.replace(tag,getStartTagHTML(element.getStartTag());
}else if(tag.getTagType()==EndTagType.NORMAL){
if(tag.getElement()==null)
返回false;
if(elementName==HTMLElementName.LI&&!isValidLITag(标记))
返回false;
doc.replace(tag,getEndTagHTML(elementName));
}否则{
返回false;
}
返回true;
}
私有静态布尔值isValidLITag(标记标记){
元素parentElement=tag.getElement().getParentElement();
if(parentElement==null
||parentElement.getStartTag().getUserData()!=有效的\u标记)
返回false;
返回parentElement.getName()==HTMLElementName.UL
||parentElement.getName()==HTMLElementName.OL;
}
私有静态void reencodeTextSegment(源源、输出文档文档、,
整数开始,整数结束){
如果(开始>=结束)
返回;
段文本段=新段(源、开始、结束);
字符串encodedText=encode(解码(文本段));
文件替换(文本段,编码文本);
}
私有静态字符序列getStartTagHTML(StartTag StartTag){
StringBuilder sb=新的StringBuilder();
sb.append(“看一看,它具有内置的标记平衡功能。
另外,请检查Nekohtml的自定义筛选器部分。它是一个非常好的html解析器。

“白名单就是要走的路”,对,我同意:)