Golang xml unmarshal html表

时间:2017-05-17 06:36:15

标签: html xml go xml-parsing html-parsing

我有一个简单的HTML表格,并且想要获取所有单元格值,即使它是HTML代码。

尝试使用xml unmarshal,但没有获得正确的struct标签,值或属性。

import (
    "fmt"
    "encoding/xml"
)

type XMLTable struct {
XMLName xml.Name `xml:"TABLE"`
    Row []struct{
        Cell string `xml:"TD"`
    }`xml:"TR"`
}

func main() {
    raw_html_table := `
    <TABLE><TR>
    <TD>lalalal</TD>
    <TD>papapap</TD>
    <TD>fafafa</TD>
    <TD>
    <form action=\"/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method=POST>
    <input type=hidden name=acT value=\"Dev\">
    <input type=hidden name=acA value=\"Anyval\">
    <input type=submit name=submit value=Stop>
    </form>
    </TD>
    </TR>
    </TABLE>`

    table := XMLTable{}
    fmt.Printf("%q\n", []byte(raw_html_table)[:15])
    err := xml.Unmarshal([]byte(raw_html_table), &table)
    if err != nil {
        fmt.Printf("error: %v", err)
    }
}

作为附加信息,我不关心单元格内容,如果它是HTML代码(仅采用[]byte / string值)。所以我可能会在解组之前删除单元格内容,但这种方式也不是那么容易。

欢迎使用标准golang库的任何建议。

2 个答案:

答案 0 :(得分:3)

坚持使用标准库

您的输入不是有效的XML,因此即使您正确建模,也无法解析它。

首先,您使用原始string literal将输入HTML定义为string,而原始字符串文字不能包含转义符。例如:

<form action=\"/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method=POST>

您无法在原始字符串文字中使用\"(您可以,但这意味着正是这2个字符),而且您不必使用简单的引号: "

接下来,在XML中,如果不将其值放在引号中,则不能拥有属性。

第三,每个元素必须具有匹配的结束元素,而您的<input>元素不会关闭。

例如,这一行:

<input type=hidden name=acT value=\"Dev\">

必须更改为:

<input type="hidden" name="acT" value="Dev" />

好的,在这些之后输入是一个有效的XML。

如何建模?这很简单:

type XMLTable struct {
    Rows []struct {
        Cell string `xml:",innerxml"`
    } `xml:"TR>TD"`
}

用于解析和打印<TD>元素内容的完整代码:

raw_html_table := `
<TABLE><TR>
<TD>lalalal</TD>
<TD>papapap</TD>
<TD>fafafa</TD>
<TD>
<form action="/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method="POST">
<input type="hidden" name="acT" value="Dev" />
<input type="hidden" name="acA" value="Anyval" />
<input type="submit" name="submit" value="Stop" />
</form>
</TD>
</TR>
</TABLE>`

table := XMLTable{}
err := xml.Unmarshal([]byte(raw_html_table), &table)
if err != nil {
    fmt.Printf("error: %v\n", err)
}

fmt.Println("count:", len(table.Rows))
for _, row := range table.Rows {
    fmt.Println("TD content:", row.Cell)
}

输出(在Go Playground上尝试):

count: 4
TD content: lalalal
TD content: papapap
TD content: fafafa
TD content: 
    <form action="/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method="POST">
    <input type="hidden" name="acT" value="Dev" />
    <input type="hidden" name="acA" value="Anyval" />
    <input type="submit" name="submit" value="Stop" />
    </form>

使用正确的HTML解析器

如果您不想或不想更改输入HTML,或者您想要处理所有HTML输入而不仅仅是有效的XML,您应该使用正确的HTML解析器而不是将输入视为XML

查看https://godoc.org/golang.org/x/net/html以获取符合HTML5的标记器和解析器。

答案 1 :(得分:0)

一旦您的输入是有效的HTML(您的代码段在属性中缺少引号),您就可以配置xml.Decoder实体和autoclose地图(并使其非严格),这将最终起作用:

Run my modified version here

package main

import (
    "encoding/xml"
    "fmt"
    "strings"
)

type XMLTable struct {
    Rows []struct {
        Cell string `xml:",innerxml"`
    } `xml:"TR>TD"`
}

func main() {
    raw_html_table := `
    <TABLE><TR>
    <TD>lalalal</TD>
    <TD>papapap</TD>
    <TD>fafafa</TD>
    <TD>
    <form action="/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method="POST">
    <input type="hidden" name="acT" value="Dev">
    <input type="hidden" name="acA" value="Anyval">
    <input type="submit" name="submit" value="Stop">
    </form>
    </TD>
    </TR>
    </TABLE>`

    table := XMLTable{}
    decoder := xml.NewDecoder(strings.NewReader(raw_html_table))
    decoder.Entity = xml.HTMLEntity
    decoder.AutoClose = xml.HTMLAutoClose   
    decoder.Strict = false

    err := decoder.Decode(&table)
    if err != nil {
        fmt.Printf("error: %v", err)
    }
    fmt.Printf("%#v\n", table)
}