首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检索元素的"outerxml“(如innerxml,但包含元素本身)

检索元素的"outerxml“(如innerxml,但包含元素本身)
EN

Stack Overflow用户
提问于 2016-11-09 23:46:02
回答 2查看 234关注 0票数 1

我有一个用于输入流的Go程序,即os.Stdin:一个非常大的XML文件,所以我不能一次性处理它。

我希望提取所有具有某种性质的XML元素,以便进行后处理。

我不难识别要提取的元素,并获得相关的开始和结束元素。但是,我不知道如何将整个元素转储为字符串,而不仅仅是内部XML。

例如,假设我有以下XML:

代码语言:javascript
复制
<a>
  <b somethingUseful="1">
    <c>Hello</c>
    <d>world</d>
  </b>
  <e>
    <foo/>
  </e>
  <!-- Imagine there were 1 billion lines in between -
       I need to stream this! -->
  <b somethingUseful="321">
    <c>Hello again</c>
  </b>
</a>

在本例中,我希望从开始到完成输出每个<b>元素。

通过使用innerxmlDecodeElement,我能够以流媒体的方式实现这一目标:

代码语言:javascript
复制
Here comes a B:

    <c>Hello</c>
    <d>world</d>

Here comes a B:

    <c>Hello again</c>

如此接近,但它缺少了<b>标记(和属性)本身。在不牺牲解码的流特性的情况下,我还没有弄清楚如何完成最后一步。

明确地说,我想要的输出是这样的:

代码语言:javascript
复制
Here comes a B:
  <b somethingUseful="1">
    <c>Hello</c>
    <d>world</d>
  </b>
Here comes a B:
  <b somethingUseful="321">
    <c>Hello again</c>
  </b>

这里有一个操场,阐述了这个例子,以及我为实现这一目标所做的工作:

1pa9j

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-11-10 11:15:47

受@nothingmuch的decoder.InputOffset用法的启发,我使用TeeReader将输入Reader分成两部分:通过解码器解析的标准和用于输出确切元素的缓冲区(在遇到元素之前和之后,该缓冲区位于decoder.InputOffset之间)。

为了最大限度地减少内存使用,缓冲区一直被清除,直到我们知道不可能匹配为止。我们保持抵消,以跟踪这一点。这种增加的复杂性是必要的,因为解码器可以在手边的令牌之前从读取器中获取字节,所以我们需要小心,不要清除我们实际需要的东西。

因此,额外的内存使用量仅限于:

  1. 最大的两个令牌,它们可能同时存储在缓冲区中,然后才被清除回一个。
  2. 要输出的实际元素的大小。

下面是一个更新的操场,提供了解决方案:

https://play.golang.org/p/H8WVDWI57r

票数 2
EN

Stack Overflow用户

发布于 2016-11-10 04:38:07

一种相当粗糙的方法是保存偏移量并读取这些字节,方法是在开始元素之前和结束元素之后向解码器请求偏移量

请参阅这个操场的例子,它将读取器排入两个管道,其中一个管道进入XML解码器,而另一个管道被缓冲,然后用于提取与XML元素对应的字节范围。

然后,XML解码例程在通道上写入一对偏移量,另一个线程使用该通道从读取器流的副本中跳过或输出感兴趣的区域。这可能要比我所做的黑客工作更认真,即使用堆栈和匹配筛选条件。

这个解决方案假定Seek/ReadAt是不可行的,回想起来我可能做得太过了,如果您只打开该文件两次,假设它是一个文件,这会简单得多。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40517885

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档