2012-11-10 9 views
13

Ich mache einen Dokumentgenerator aus YAML-Daten, die angeben würde, aus welcher Zeile der YAML-Datei jedes Element generiert wird. Was ist der beste Weg, dies zu tun? Wenn also die YAML-Datei ist wie folgt:Parsing YAML, Rückgabe mit Zeilennummer

- key1: item 1 
    key2: item 2 
- key1: another item 1 
    key2: another item 2 

ich so etwas wie dies will:

[ 
    {'__line__': 1, 'key1': 'item 1', 'key2': 'item 2'}, 
    {'__line__': 3, 'key1': 'another item 1', 'key2': 'another item 2'}, 
] 

Ich verwende PyYAML zur Zeit, aber jede andere Bibliothek ist in Ordnung, wenn ich es von Python verwenden kann.

Antwort

10

ich es durch Zugabe von Haken zu Composer.compose_node und Constructor.construct_mapping gemacht haben:

import yaml 
from yaml.composer import Composer 
from yaml.constructor import Constructor 

def main(): 
    loader = yaml.Loader(open('data.yml').read()) 
    def compose_node(parent, index): 
     # the line number where the previous token has ended (plus empty lines) 
     line = loader.line 
     node = Composer.compose_node(loader, parent, index) 
     node.__line__ = line + 1 
     return node 
    def construct_mapping(node, deep=False): 
     mapping = Constructor.construct_mapping(loader, node, deep=deep) 
     mapping['__line__'] = node.__line__ 
     return mapping 
    loader.compose_node = compose_node 
    loader.construct_mapping = construct_mapping 
    data = loader.get_single_data() 
    print(data) 
+0

Danke - das hat perfekt funktioniert und ist sehr nützlich, wenn es um Fehlerberichte geht. –

2

Für weitere Inspiration, hier ist mein Code für diese. Es enthält mehr Informationen als oben angefordert, da es die Standortinformationen mit start_mark, end_mark auf jedem dict/list/unicode (mit den Unterklassen dict_node, list_node, unicode_node) berichtet.

https://gist.github.com/dagss/5008118

3

Wenn Sie ruamel.yaml verwenden> = 0,9 (davon bin ich der Autor), und verwenden Sie die RoundTripLoader, können Sie die Eigenschaft zugreifen lc auf Kollektionsteile Zeile und Spalte zu bekommen, wo sie in der gestartet Quelle YAML:

def test_item_04(self): 
    data = load(""" 
    # testing line and column based on SO 
    # http://stackoverflow.com/questions/13319067/ 
    - key1: item 1 
     key2: item 2 
    - key3: another item 1 
     key4: another item 2 
     """) 
    assert data[0].lc.line == 2 
    assert data[0].lc.col == 2 
    assert data[1].lc.line == 4 
    assert data[1].lc.col == 2 

(Zeile und Spalte beginnen bei 0 zu zählen).

This answer zeigen, wie das lc Attribut zu Zeichenfolgetypen während des Ladens hinzugefügt wird.

+0

Konnte einen Weg finden, dies zu funktionieren, wenn die Liste innerhalb einer geordneten Karte ist, wie in 'Schlüssel1: !! omap \ n - Schlüssel4: Gegenstand2 \ n - Schlüssel3: Gegenstand3' ist es nicht möglich auf' Schlüssel4' zuzugreifen und 'key3' Zeilennummern. – zezollo

+0

@zezollo Eine Orderedmap wird standardmäßig nicht in eine CommentedMap-Struktur geladen und hat daher nicht das Attribut 'LC'. Sie müssten die! Omap loading als Unterklasse von CommentedMap registrieren. Das ist machbar, aber mehr als ich in einem Kommentar antworten kann. Sie sollten eine neue Frage stellen, wenn Sie nicht herausfinden, wie das geht. – Anthon

+0

In der Tat kann ich das nicht herausfinden. Ich habe nur einen "schmutzigen" Workaround gefunden, um die Zeilennummern zu erhalten. Frage gestellt [hier] (https://stackoverflow.com/questions/45716281/parsing-yaml-get-line-numbers-even-inordered-maps). – zezollo