Sie haben eine XY Problem gefragt. Sie denken, dass das Problem ist, dass Sie einen fehlenden Namespace hinzufügen müssen; Das eigentliche Problem ist, dass die Datei, die Sie analysieren möchten, keine gültige XML-Datei ist.
require 'nokogiri'
doc = Nokogiri.XML(IO.read('0001558370-15-001143.txt'))
doc.errors.length
#=> 5716
Zum Beispiel kann das <ACCEPTANCE-DATETIME>
‚Element‘ geöffnet auf der Linie 3 ist nie geschlossen, und auf der Linie 16 gibt es einen rohen Ampersand im Text:
STANDARD INDUSTRIAL CLASSIFICATION: ELECTRIC HOUSEWARES & FANS [3634]
die sollte als Einheit entkommen sein.
Allerdings hat das Dokument gültige XML-Fragmente innerhalb es! Insbesondere gibt es ein XML-Dokument, das den Namespace xmlns:us-gaap
aus den Zeilen 27243-49312 definiert. Lassen Sie uns nur das herausfinden, indem wir nur das Wissen verwenden, dass das Wurzelelement den gewünschten Namespace definiert, und die Annahmen, dass kein Element mit demselben Namen innerhalb des Dokuments verschachtelt ist und dass das Wurzelelement kein unescaped >
Zeichen enthält irgendein Attribut. (Diese Annahmen sind für diese Datei gültig, kann aber nicht für jede XML-Datei gültig.)
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
Der obige Code behandelt den Fall, in dem es mehr als ein XML-Dokument in der txt-Datei sein, obwohl in dieser Fall, es gibt nur einen.
Decoded, die gaap_finder
regex sagt dies:
%r{...}m
- dies ist ein regulärer Ausdruck (das die Schrägstriche darin, unescaped) mit "mehrzeiligen Modus", in dem eine Periode Zeilenumbrüche übereinstimmen
(...)
- erfaßt alles, was wir finden
<
- beginnen mit einem wörtlichen „weniger als“ Symbol
(\w+)
- findet ein oder mehr Wortzeichen (den Tag nennen), und speichern Sie sie
- die Wortzeichen muss ein Leerzeichen gefolgt werden (wichtig, die <xsd:xbrl ...>
Element in dieser Datei erfassen zu vermeiden)
[^>]+
- gefolgt von einem oder mehreren Zeichen, die nicht ein „Größer ist als“Symbol (um sicherzustellen, dass wir in dem gleichen Elemente bleiben, die uns in gestartet)
xmlns:us-gaap\s*=
- gefolgt von dieser wörtlichen Namespace-Deklaration (das Leerzeichen hast trennen sie von dem Gleichheitszeichen)
.+?
- gefolgt von irgendetwas (so wenig wie möglich) ...
</\2>
- ... bis Sie einen End-Tag mit dem gleichen Namen wie das, was wir für den Namen des Start-Tages erfaßt
Aufgrund der Art und Weise scan
funktioniert, wenn die Regex Gruppen hat die Erfassung, jedes Ergebnis ist ein Array mit zwei Elementen, wobei das erste Element das gesamte erfasste XML und das zweite Element der Name des Tags ist, das wir erfasst haben (was wir "verwerfen", indem wir es der Variablen _
zuweisen).
Wenn Sie über Ihr Capturing weniger Magie sein, wird das Text-Dateiformat immer jedes XML-Dokument in <XBRL>...</XBRL>
zu wickeln. Also, Sie dies tun könnten jede XML-Datei zu verarbeiten (es gibt sieben, fünf davon passiert keinen us-gaap
Namensraum haben):
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)
Statt einer Verbindung, die minimalen Daten extrahieren, das Problem zu demonstrieren und setzen es in deine Frage. Welchen Code haben Sie geschrieben, um dieses Problem zu lösen? Bitte lesen Sie "[mcve]". Wir benötigen die minimale Eingabe und ein Beispiel für die gewünschte Ausgabe. –
Danke für die Warnung, ich füge ein minimales Beispiel hinzu. – ironsand