2016-06-30 20 views
0

Ich habe folgendes Beispiel Dokument:Wie Daten aus den Tags ziehen basierend auf anderen 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 Verwendung Ich möchte den Wert zwischen dem <PersonFirstNm>, <PersonLastNm> und <irs:SSN> für jeden <Form1095CUpstreamDetail> extrahieren basierend auf dem <RecordId>.

Ich habe versucht, Namespaces zu entfernen. Ich habe ein kleines Snippet gepostet, aber ich habe viele Iterationen versucht, ohne Erfolg durch das XML zu arbeiten. Dies ist das erste Mal, dass ich XML benutze, also merke ich, dass ich wahrscheinlich etwas Einfaches vermisse.

Wenn ich meine XPath gesetzt:

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

Ich scheine keine Zuordnung zu haben zwischen den RecordId und den Tags oben erwähnt, und ich bin fest auf dem nächsten zu gehen.

Die Felder sind nicht als Kinder für die RecordId aufgeführt, so dass ich nicht darüber nachdenken kann, wie sie ihre Werte erhalten. Ich füge das vollständige Dokument als Beispiel ein, um sicherzustellen, dass ich nichts ausschließe.

Ich habe ein Array von Werten, und ich möchte die drei oben genannten Tags ziehen, wenn die RecordId innerhalb des Arrays von Zahlen enthalten ist.

+1

Bitte lesen Sie "[mcve]", dann reduzieren Sie Ihre XML-Eingabe auf das absolute, nackte Minimum, das notwendig ist, um das Problem zu demonstrieren. Alles andere darüber hinaus verschwendet unsere Zeit, Ihnen zu helfen. Nehmen Sie sich auch Zeit, Variablen im Text zu formatieren. Das hilft denjenigen, die helfen, und denjenigen, die in Zukunft ähnliche Lösungen suchen, die Frage zu verstehen. –

+0

Das XML ist ungültig, was zu Problemen beim Parsen führen kann.Nicht übereinstimmende Tags erzwingen, dass der Parser Korrekturen vornimmt und versucht, etwas Nützliches bereitzustellen, aber dieser Prozess kann dazu führen, dass Tags fehlen. Sie müssen herausfinden, wie Sie das XML vor dem Parsen reparieren können, wenn Sie sicherstellen möchten, dass Ihr Code einen guten Ausgangspunkt hat. Nokogiri 'submission_doc.errors' sollte nach dem Parsen" Eröffnungs- und Endmarkierung nicht übereinstimmen: Form1094CUpstreamDetail-Zeile 3 und Form1095CUpstreamDetail "zurückgeben. –

+0

Vielen Dank @theTinMan Ich hätte diesen Fehlern mehr Aufmerksamkeit schenken sollen, es stellte sich heraus, dass die Quelle die Dateien manipulierte, bevor sie sie zur Verfügung stellten und meine XML-Probleme verursachten. Ich habe die oben genannten bearbeitet, um zu versuchen, Ihre Anfrage zu erfüllen, da ich in der Lage war, die Informationen, die Sie und die akzeptierte Antwort zur Verfügung gestellt haben, weiter zu verwenden. Lektion gelernt und entschuldigt sich für die Kopfschmerzen und Probleme verursacht. – StoutPanda

Antwort

0

Nokogiri macht hilft es ziemlich einfach zu tun, was Sie wollen (ist die XML-Annahme syntaktisch korrekt). Ich würde so etwas wie:

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"}] 

Während es möglich, dies mit XPath zu tun, was zu mehr führen Nokogiri Implementierung von CSS-Selektoren neigt dazu, leicht Selektoren lesen, was zu leichter übersetzt zu erhalten, die eine sehr gute Sache ist .

Sie werden die Verwendung von | in 'irs|SSN' sehen, die Nokogiris Methode ist, einen Namespace für CSS zu definieren. Dies ist in "Namespaces" dokumentiert.

+0

Danke. Nach dem Zurückgehen zur Quelle und dem Erhalten der festen XML lieferte dies ein viel besser lesbares Skript, das leicht erweitert werden kann. – StoutPanda

0

Zunächst wird der XML-Validator meldet Fehler

Der Standard (kein Präfix) Namespace URI für XPath-Abfragen ist immer '' und es kann nicht neu definiert werden ‚urn: uns: gov: Treasury: irs: ext: aca: Luft: 7,0 '.

so müssen Sie diese Standardeinstellung xmlns auf "" setzen.

Sie können diesen Code verwenden.

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 

Ausgang

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

Ich hoffe, das

+0

Vielen Dank für die Hilfe. Das hat mich genau dahin gebracht, wo ich gebraucht habe. – StoutPanda