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

时间:2016-06-30 22:38:39

标签: ruby xml nokogiri

我有以下示例文档:

<?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我想根据<PersonFirstNm>为每个<PersonLastNm>提取<irs:SSN><Form1095CUpstreamDetail><RecordId>之间的值。

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

当我设置XPath时:

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

RecordId和上面提到的标签之间似乎没有任何关联,我仍然坚持下一步去哪里。

这些字段未列为RecordId的子项,因此我无法想到如何获取其值。我以完整文件为例,以确保我不排除任何内容。

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

2 个答案:

答案 0 :(得分:0)

首先,xml验证程序报告错误

  

XPath查询的默认(无前缀)命名空间URI始终是&#39;&#39;它不能被重新定义为“我们:gov:treasury:irs:ext:aca:air:7.0&#39;。

因此您必须将此默认xmlns设置为&#34;&#34;。

您可以使用此代码。

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

<强>输出

StuID
------
1
2

我希望这会有所帮助

答案 1 :(得分:0)

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命名空间的方式。这记录在&#34; Namespaces&#34;。