gpt4 book ai didi

ruby - 如何将命名空间添加到现有的 xml 文件

转载 作者:数据小太阳 更新时间:2023-10-29 07:52:06 24 4
gpt4 key购买 nike

我想打开这个文件并获取所有以 us-gaap 开头的元素。

ftp://ftp.sec.gov/edgar/data/916789/0001558370-15-001143.txt

为了获取元素,我试过这样:

str = '<html><body><us-gaap:foo>foo</us-gaap:foo></body></html>'
doc = Nokogiri::XML(File.read(str))
doc.xpath('//us-gaap:*')
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: //us-gaap:*
from /Users/ironsand/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/nokogiri-1.6.7.2/lib/nokogiri/xml/searchable.rb:165:in `evaluate'

doc.namespaces 返回 {},所以我想我必须添加命名空间 us-gaap

有一些关于“使用 Nokogiri 添加 namespace ”的问题,但看起来像是关于如何创建一个新的 XML 文档,而不是如何将 namespace 添加到现有文档。

如何向现有文档添加命名空间?

我知道我可以通过 Nokogiri::XML::Document#remove_namespaces! 删除命名空间,但我不想使用它,因为它也删除了必要的信息。

最佳答案

你问了一个XY Problem .您认为问题是您需要添加缺少的 namespace ;真正的问题是您尝试解析的文件不是有效的 XML。

require 'nokogiri'
doc = Nokogiri.XML( IO.read('0001558370-15-001143.txt') )
doc.errors.length
#=> 5716

例如,<ACCEPTANCE-DATETIME>在第 3 行打开的“元素”永远不会关闭,在第 16 行的文本中有一个原始的符号:
STANDARD INDUSTRIAL CLASSIFICATION: ELECTRIC HOUSEWARES & FANS [3634]
应该作为一个实体进行转义。

但是,文档中 包含有效的 XML 片段!特别是,有一个 XML 文档定义了 xmlns:us-gaap命名空间,来自第 27243-49312 行。让我们只提取它,仅使用根元素定义我们想要的 namespace 的知识,以及文档中没有嵌套同名元素的假设,并且根元素没有未转义的 >任何属性中的字符。 (这些假设适用于此文件,但可能不适用于每个 XML 文件。)

txt = IO.read('0001558370-15-001143.txt')
gaap_finder = %r{(<(\w+) [^>]+xmlns:us-gaap=.+?</\2>)}m
txt.scan(gaap_finder) do |xml,_|
doc = Nokogiri.XML( xml )
gaaps = doc.xpath('//us-gaap:*')
p gaaps.length
#=> 569
end

上面的代码处理了 txt 文件中可能有多个 XML 文档的情况,尽管在本例中只有一个。

解码后,gaap_finder正则表达式是这样说的:

  • %r{...}m — 这是一个具有“多行模式”的正则表达式(允许在其中使用斜杠,未转义),其中句点将匹配换行符
  • (...) — 捕捉我们发现的一切
  • < — 以文字“小于”符号开头
  • (\w+) — 找到一个或多个单词字符(标签名称),并保存
  • — 单词字符后面必须跟一个空格(重要的是避免捕获此文件中的 <xsd:xbrl ...> 元素)
  • [^>]+ — 后跟一个或多个不是“大于”符号的字符(以确保我们保持在我们开始的同一元素中)
  • xmlns:us-gaap\s*= — 后跟此文字命名空间声明(可以用空格将其与等号分隔开)
  • .+? — 然后是任何东西(尽可能少)...
  • </\2> — ...直到您看到一个与我们捕获的起始标签同名的结束标签

因为方式scan当正则表达式具有捕获组时工作,每个结果都是一个双元素数组,其中第一个元素是整个捕获的 XML,第二个元素是我们捕获的标签的名称(我们通过将其分配给_ 变量)。


如果您想减少捕获的魔力,文本文件格式似乎总是将每个 XML 文档包装在 <XBRL>...</XBRL> 中。 .因此,您可以这样做来处理每个 XML 文件(共有七个,其中五个碰巧没有任何 us-gaap namespace ):

txt   = IO.read('0001558370-15-001143.txt')
xbrls = %r{(?<=<XBRL>).+?(?=</XBRL>)}m # find text inside <XBRL>…</XBRL>
txt.scan(xbrls) do |xml|
doc = Nokogiri.XML( xml )
if doc.namespaces["xmlns:us-gaap"]
gaaps = doc.xpath('//us-gaap:*')
p gaaps.length
end
end
#=> 569
#=> 0 (for the XML Schema document that defines the namespace)

关于ruby - 如何将命名空间添加到现有的 xml 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36397437/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com