2012-11-10 42 views
13

Tôi đang tạo trình tạo tài liệu từ dữ liệu YAML, sẽ chỉ định dòng của tệp YAML mà mỗi mục được tạo ra. Cách tốt nhất để làm việc này là gì? Vì vậy, nếu file YAML là như thế này:Phân tích cú pháp YAML, quay lại với số dòng

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

Tôi muốn một cái gì đó như thế này:

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

Tôi hiện đang sử dụng PyYAML, nhưng bất kỳ thư viện khác là OK nếu tôi có thể sử dụng nó từ Python.

Trả lời

10

Tôi đã thực hiện nó bằng cách móc thêm vào Composer.compose_nodeConstructor.construct_mapping:

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

Cảm ơn - điều này hoạt động hoàn hảo và rất hữu ích khi nói đến báo cáo lỗi. –

2

Đối với nguồn cảm hứng hơn nữa, đây là mã của tôi cho việc này. Nó chứa nhiều thông tin hơn yêu cầu ở trên vì nó báo cáo thông tin vị trí bằng cách sử dụng start_mark, end_mark trên mỗi dict/list/unicode (sử dụng dict_node, list_node, unicode_node subclasses, tương ứng).

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

3

Nếu bạn đang sử dụng ruamel.yaml> = 0,9 (trong đó tôi là tác giả), và sử dụng RoundTripLoader, bạn có thể truy cập vào các tài sản lc vào các mặt hàng bộ sưu tập để có được dòng và cột nơi họ bắt đầu vào nguồn 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 

(bắt đầu dòng và cột ở 0).

This answer cho biết cách thêm thuộc tính lc vào loại chuỗi trong khi tải.

+0

Không thể tìm cách để cho tác phẩm này nếu danh sách nằm trong bản đồ đã sắp xếp, như trong 'key1: !! omap \ n - key4: item2 \ n - key3: item3' không thể truy cập vào 'key4' và số dòng 'key3'. – zezollo

+0

@zezollo một bản đồ đã sắp xếp không theo mặc định được tải vào cấu trúc CommentedMap và do đó không có thuộc tính 'lc'. Bạn sẽ phải đăng ký tải omap! Làm lớp con của CommentedMap. Đó là doable, nhưng nhiều hơn tôi có thể trả lời trong một bình luận. Bạn nên đăng một câu hỏi mới nếu bạn không thể tìm ra cách để làm điều đó. – Anthon

+0

Thực ra tôi không thể hình dung điều này. Tôi chỉ tìm thấy cách giải quyết "bẩn thỉu" để lấy số dòng. Câu hỏi được yêu cầu [ở đây] (https://stackoverflow.com/questions/45716281/parsing-yaml-get-line-numbers-even-in-ordered-maps). – zezollo

Các vấn đề liên quan