当前位置: 首页 > 知识库问答 >
问题:

如何通过io.Reader转换HTML实体

廖诚
2023-03-14

My Go程序发出HTTP请求,其响应主体是大型JSON文档,其字符串编码与字符

示例响应可能如下所示:

{"name":"A&B","comment":"foo&bar"}

其对应对象如下:

pkg.Object{Name:"A&B", Comment:"foo&bar"}

文档有各种形状,因此在解码后转换超文本标记语言实体是不可行的。理想情况下,可以通过将响应正文阅读器包装在另一个执行转换的阅读器中来完成。

有没有一种简单的方法来包装< code>http。一些io中的Response.Body。ReadCloser,它替换< code >的所有实例

我怀疑这可以用< code>x/text/transform来实现,但是不要马上看到如何实现。特别是,我担心一个实体跨越几批字节的边缘情况。也就是说,一批以< code >结束

共有2个答案

万俟铭
2023-03-14

您需要创建一个transform.Transformer来替换您的字符。

因此,我们需要一个将旧的 [] 字节转换为新的 [] 字节,同时保留所有其他数据。实现可能如下所示:

type simpleTransformer struct {
    Old, New []byte
}

// Transform transforms `t.Old` bytes to `t.New` bytes.
// The current implementation assumes that len(t.Old) >= len(t.New), but it also seems to work when len(t.Old) < len(t.New) (this has not been tested extensively)
func (t *simpleTransformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
    // Get the position of the first occurance of `t.Old` so we can replace it
    var ci = bytes.Index(src[nSrc:], t.Old)

    // Loop over the slice until we can't find any occurances of `t.Old`
    // also make sure we don't run into index out of range panics
    for ci != -1 && nSrc < len(src) {
        // Copy source data before `nSrc+ci` that doesn't need transformation
        copied := copy(dst[nDst:nDst+ci], src[nSrc:nSrc+ci])
        nDst += copied
        nSrc += copied

        // Copy new data with transformation to `dst`
        nDst += copy(dst[nDst:nDst+len(t.New)], t.New)

        // Skip the rest of old bytes in the next iteration
        nSrc += len(t.Old)

        // search for the next occurance of `t.Old`
        ci = bytes.Index(src[nSrc:], t.Old)
    }

    // Mark the rest of data as not completely processed if it contains a start element of `t.Old`
    // (e.g. if the end is `&amp` and we're looking for `&amp;`)
    // This data will not yet be copied to `dst` so we can work with it again
    // If it is at the end (`atEOF`), we don't need to do the check anymore as the string might just end with `&amp` 
    if bytes.Contains(src[nSrc:], t.Old[0:1]) && !atEOF {
        err = transform.ErrShortSrc
        return
    }

    // Copy rest of data that doesn't need any transformations
    // The for loop processed everything except this last chunk
    copied := copy(dst[nDst:], src[nSrc:])
    nDst += copied
    nSrc += copied

    return nDst, nSrc, err
}

// To satisfy transformer.Transformer interface
func (t *simpleTransformer) Reset() {}

实现必须确保它处理在Transform方法的多个调用之间分割的字符,这就是它返回转换的原因。ErrShortSrc告诉转换。读卡器需要有关下一个字节的更多信息。

这现在可用于替换流中的字符:

var input = strings.NewReader(`{"name":"A&amp;B","comment":"foo&amp;bar"}`)
r := transform.NewReader(input, &simpleTransformer{[]byte(`&amp;`), []byte(`&`)})
io.Copy(os.Stdout, r) // Instead of io.Copy, use the JSON decoder to read from `r`

输出:

{"name":"A&B","comment":"foo&bar"}

你也可以在Go Playground上看到这一点。

车子平
2023-03-14

如果您不想依赖像transform这样的外部包。阅读器您可以编写自定义io。读卡器包装器。

以下将处理find元素可能跨越两个Read()调用的边缘情况:

type fixer struct {
    r        io.Reader // source reader
    fnd, rpl []byte    // find & replace sequences
    partial  int       // track partial find matches from previous Read()
}

// Read satisfies io.Reader interface
func (f *fixer) Read(b []byte) (int, error) {
    off := f.partial
    if off > 0 {
        copy(b, f.fnd[:off]) // copy any partial match from previous `Read`
    }

    n, err := f.r.Read(b[off:])
    n += off

    if err != io.EOF {
        // no need to check for partial match, if EOF, as that is the last Read!
        f.partial = partialFind(b[:n], f.fnd)
        n -= f.partial // lop off any partial bytes
    }

    fixb := bytes.ReplaceAll(b[:n], f.fnd, f.rpl)

    return copy(b, fixb), err // preserve err as it may be io.EOF etc.
}

连同此助手(可能需要一些优化):

// returns number of matched bytes, if byte-slice ends in a partial-match
func partialFind(b, find []byte) int {
    for n := len(find) - 1; n > 0; n-- {
        if bytes.HasSuffix(b, find[:n]) {
            return n
        }
    }
    return 0 // no match
}

工作游乐场示例。

注意:要测试边缘情况逻辑,可以使用窄读取器来确保短读取并强制在读取之间拆分匹配,如下所示:验证游乐场示例

 类似资料:
  • 本文向大家介绍通过代码实现如下转换(进制之间转换)相关面试题,主要包含被问及通过代码实现如下转换(进制之间转换)时的应答技巧和注意事项,需要的朋友参考一下  

  • 问题内容: 我维护着一个公告板,用于将富文本消息保存为HTML。现在,我需要将所有这些消息迁移到需要HTML的BBCode表示的Joomla Kunena公告板上。 是否有任何库可以将HTML干净地转换为BBCode。有大量的脚本,可以将BBCode转换为HTML,但是没有相反的方法。 谢谢… 问题答案: 它应该可以在 文本输出模式下 与XSLT一起 使用 : 要到达那里,解析HTML并使用内置的

  • 问题内容: 我正在编写一个长期运行的任务,该任务多次从mongodb(使用mgo)获取。然后使用此模块将其写入xlsx文件。然后使用重新读取,然后将其存储到我的ftp服务器中。 函数会消耗大量内存,因此,我认为应该有一种方法不保存文件,而是将数据从xlsx.Write直接传递到ftp.Store。(如果我可以同时进行流传输,那将是完美的,因为在将它们发送到Stor函数之前,不必将所有文档都保留在服

  • 问题内容: 我有以下内容: 我正在寻找一个Javascript函数来转换文本,以便每个特殊字母都由其HTML实体序列表示,如下所示: 该函数不仅应转义该示例的字母,而且还应转义所有这些字母。 您将如何实现?是否有任何现有功能?(很简单,因为首选没有框架的解决方案)顺便说一句:是的,我已经看到了这个问题,但是并不能满足我的需求。 问题答案: 借助bucabay的帮助和创建我自己的功能的建议,我创建了

  • null 出什么问题了?

  • 我想修改html文件转换为PDF。 目前我使用“ITExtrenderer”将html文件转换为pdf。 当前: 1-但以后我需要修改html文件,然后再生成pdf,为此我想提取html文件内容并转换成字符串,然后我替换字符串上的一些文本html: 2-然后从html中替换字符串中的标记 主: 但现在我不知道如何用html文件的旧html字符串替换新字符串