如何根据其他标签从标签中提取数据

How to pull data from tags based on other tags

我有以下示例文档:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<n1:Form109495CTransmittalUpstream xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:irs="urn:us:gov:treasury:irs:common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage IRS-Form1094-1095CTransmitterUpstreamMessage.xsd" xmlns:n1="urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage">
<Form1095CUpstreamDetail RecordType="String" lineNum="1">
<RecordId>1</RecordId>
<CorrectedInd>0</CorrectedInd>
<irs:TaxYr>2015</irs:TaxYr>
<EmployeeInfoGrp>
<OtherCompletePersonName>
<PersonFirstNm>JOHN</PersonFirstNm>
<PersonMiddleNm>B</PersonMiddleNm>
<PersonLastNm>Doe</PersonLastNm>
</OtherCompletePersonName>
<PersonNameControlTxt/>
<irs:TINRequestTypeCd>INDIVIDUAL_TIN</irs:TINRequestTypeCd>
<irs:SSN>123456790</irs:SSN>
</Form1095CUpstreamDetail>
<Form1095CUpstreamDetail RecordType="String" lineNum="1">
<RecordId>2</RecordId>
<CorrectedInd>0</CorrectedInd>
<irs:TaxYr>2015</irs:TaxYr>
<EmployeeInfoGrp>
<OtherCompletePersonName>
<PersonFirstNm>JANE</PersonFirstNm>
<PersonMiddleNm>B</PersonMiddleNm>
<PersonLastNm>DOE</PersonLastNm>
</OtherCompletePersonName>
<PersonNameControlTxt/>
<irs:TINRequestTypeCd>INDIVIDUAL_TIN</irs:TINRequestTypeCd>
<irs:SSN>222222222</irs:SSN>
</EmployeeInfoGrp>
</Form1095CUpstreamDetail>
</n1:Form109495CTransmittalUpstream>

使用 Nokogiri,我想根据 <RecordId> 为每个 <Form1095CUpstreamDetail> 提取 <PersonFirstNm><PersonLastNm><irs:SSN> 之间的值。

我也尝试删除命名空间。我发布了一个小片段,但我尝试了很多次 XML 的迭代,但都没有成功。这是我第一次使用 XML,所以我意识到我可能遗漏了一些简单的东西。

当我设置 XPath 时:

require 'nokogiri'
submission_doc = Nokogiri::XML(open('1094C_Request.xml'))
submissions = submission_doc.remove_namespaces
nodes = submission.xpath('//Form1095CUpstreamDetail')

RecordId 和上面提到的标签之间似乎没有任何关联,我不知道下一步该去哪里。

这些字段未列为 RecordId 的子字段,所以我想不出如何获取它们的值。我以完整文档为例,以确保我没有排除任何内容。

我有一个值数组,如果 RecordId 包含在数字数组中,我想提取上面提到的三个标签。

首先 xml 验证器报告错误

The default (no prefix) Namespace URI for XPath queries is always '' and it cannot be redefined to 'urn:us:gov:treasury:irs:ext:aca:air:7.0'.

因此您必须将此默认 xmlns 设置为“”。

您可以使用此代码。

require 'nokogiri'

doc = Nokogiri::XML(open('1094C_Request.xml'))

doc.namespaces['xmlns'] = ''

details = doc.xpath("//:Form1095CUpstreamDetail")

elem_a = ["PersonFirstNm", "PersonLastNm", "irs:SSN"]

output = details.each_with_object({}) do |element, exp|
  exp[element.xpath("./:RecordId").text] = elem_a.each_with_object({}) do |elem_n, exp_h|
    exp_h[elem_n] = element.xpath(".//#{elem_n.include?(':') ? elem_n : ":#{elem_n}"}").text
  end
end

输出

p output
# {
#   "1" => {"PersonFirstNm" => "JOHN", "PersonLastNm" => "Doe", "irs:SSN" => "123456790"},
#   "2" => {"PersonFirstNm" => "JANE", "PersonLastNm" => "DOE", "irs:SSN" => "222222222"}
# }

希望对您有所帮助

Nokogiri 可以很容易地做你想做的事(假设 XML 在语法上是正确的)。我会做类似的事情:

require 'nokogiri'
require 'pp'

doc = Nokogiri::XML(<<EOT)
<n1:Form109495CTransmittalUpstream xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:irs="urn:us:gov:treasury:irs:common" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage IRS-Form1094-1095CTransmitterUpstreamMessage.xsd" xmlns:n1="urn:us:gov:treasury:irs:msg:form1094-1095Ctransmitterupstreammessage">
  <Form1095CUpstreamDetail RecordType="String" lineNum="1">
    <RecordId>1</RecordId>
    <PersonFirstNm>JOHN</PersonFirstNm>
    <PersonLastNm>Doe</PersonLastNm>
    <irs:SSN>123456790</irs:SSN>
  </Form1095CUpstreamDetail>
  <Form1095CUpstreamDetail RecordType="String" lineNum="1">
    <RecordId>2</RecordId>
    <PersonFirstNm>JANE</PersonFirstNm>
    <PersonLastNm>DOE</PersonLastNm>
    <irs:SSN>222222222</irs:SSN>
  </Form1095CUpstreamDetail>
</Form109495CTransmittalUpstream>
EOT

info = doc.search('Form1095CUpstreamDetail').map{ |form|
  {
    record_id:       form.at('RecordId').text,
    person_first_nm: form.at('PersonFirstNm').text,
    person_last_nm:  form.at('PersonLastNm').text,
    ssn:             form.at('irs|SSN').text
  }
}
pp info
# >> [{:record_id=>"1",
# >>   :person_first_nm=>"JOHN",
# >>   :person_last_nm=>"Doe",
# >>   :ssn=>"123456790"},
# >>  {:record_id=>"2",
# >>   :person_first_nm=>"JANE",
# >>   :person_last_nm=>"DOE",
# >>   :ssn=>"222222222"}]

虽然可以使用 XPath 做到这一点,但 Nokogiri 对 CSS 选择器的实现往往会产生更易于阅读的选择器,这意味着更易于维护,这是一件非常好的事情。

您将在 'irs|SSN' 中看到 | 的使用,这是 Nokogiri 为 CSS 定义名称空间的方式。这记录在“Namespaces”中。