【问题标题】:Error when parsing yaml file : found character '%' that cannot start any token解析 yaml 文件时出错:发现无法启动任何令牌的字符 '%'
【发布时间】:2017-07-05 07:38:31
【问题描述】:

我正在尝试从 yaml 文件中解析具有类似于 jinaj2 模板语法的表达式的数据,目标是删除或添加一些项目到文件中。

AddCodesList.yaml

AddCodesList:
  body:
    list:
    {% for elt in customer %}
      - code: {{ elt.code }}
        name: {{ elt.name }}
        country: {{ elt.country }}
    {% endfor %}   
  result:
    json:
      responseCode: {{ responseCode }}
      responseMsg: {{ responseMsg }}
      responseData: {{ responseData }}

parseFile.py

import ruamel.yaml
from ruamel.yaml.util import load_yaml_guess_indent

data,indent,block_seq_indent=load_yaml_guess_indent(open('AddCodesList.yaml'), preserve_quotes=True)

#delete item
del data['body']['list']['code']
#add new item
data['parameters'].insert(2, 'ssl_password','xxxxxx')#create new file
ruamel.yaml.round_trip_dump(data, open('missingCode.yaml', 'w'), explicit_start=True)

执行 parseFile.py 脚本时出现以下错误:

    Traceback (most recent call last):
      File "d:/workspace/TEST/manageItem.py", line 4, in <module>
        data, indent, block_seq_indent = load_yaml_guess_indent(open('AddCodesList.
...
        if self.check_token(ValueToken):
      File "C:\Python34\lib\site-packages\ruamel\yaml\scanner.py", line 1534, in ch
        self.fetch_more_tokens()
      File "C:\Python34\lib\site-packages\ruamel\yaml\scanner.py", line 269, in fet
        % utf8(ch), self.get_mark())
    ruamel.yaml.scanner.ScannerError: while scanning for the next token
    found character '%' that cannot start any token
      in "<unicode string>", line 4, column 6:
            {% for elt in customer %}
             ^ (line: 4)

【问题讨论】:

    标签: yaml ruamel.yaml


    【解决方案1】:

    在 YAML 中,“{”启动流式映射,因此 (%) 将成为该映射的第一个键的开始,并且该字符不允许作为第一个字符。

    通常您会先处理文件的模板,然后再应用 YAML。您不能轻易逆转该过程,因为 list 的值必须是有效的 YAML 构造。

    使其可解析的解决方案之一是将 list 的值更改为有效的 YAML,例如:

    list:
      - {% for elt in customer %}
      - code: {{ elt.code }}
        name: {{ elt.name }}
        country: {{ elt.country }}
      - {% endfor %} 
    

    或:

    list: |
        {% for elt in customer %}
          - code: {{ elt.code }}
            name: {{ elt.name }}
            country: {{ elt.country }}
        {% endfor %} 
    

    这将不再使它成为可模板化的 bij jinja2。

    您可以从 {% 更改 jinja2 中的启动序列,但这对您没有帮助(即您仍然无法获得有效的 YAML)。我目前看到的唯一真正的解决方案是完全放弃 jinja2 并使用 Python 中的一些类似对象的列表(在访问时扩展)来实现 for 循环。

    如果允许在应用 jinja2 之前始终进行预处理,您可以将文件更改为:

    AddCodesList:
      body:
        list:
        # {% for elt in customer %}
          - code: '{{ elt.code }}'
            name: '{{ elt.name }}'
            country: '{{ elt.country }}'
        # {% endfor %}   
    

    因为它会加载,但您可能需要在运行模板引擎之前将 # b{ 更改为 {

    使用单引号作为引号,在它们之间只有单引号具有特殊含义。使用双引号,您通常会得到预处理器插入的某些内容,这会使 YAML 不正确(例如,DOS/Windows 样式的完整文件路径:'C:\yaml\abc.yaml' 是正确的,但 "c:\yaml\abc.yaml" 会在 YAML 解析期间给您一个错误。

    【讨论】:

    • 谢谢你,Anthon,最后一个解决方案似乎可以接受,但有一点小改进需要 yaml parser 验证:为包含 "{{ ... }}" 的项目添加双引号,如下所示:国家:“{{ elt.country }}”
    • @bcharfi 是的,引号当然是必要的。我没有测试过那个“提议”,只看了{% 行。幸运的是,当您使用preserve_quotes=True 往返时,ruamel.yaml 会保留双引号 :-)
    【解决方案2】:

    问题通过以下结构解决:

    AddCodesList:
      body:
        list:
        # {% for elt in customer %}
          - code: "{{ elt.code }}"
            name: "{{ elt.name }}"
            country: "{{ elt.country }}"
        # {% endfor %}  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-07
      • 1970-01-01
      • 1970-01-01
      • 2017-01-24
      • 2018-06-23
      • 2020-07-22
      • 2019-06-21
      • 1970-01-01
      相关资源
      最近更新 更多