yaml格式文件

目录

安装

书写格式  YAML.rb is YAML for Ruby | Cookbook

块序列

块映射

流集合

标量

YAML 标签和 Python 类型

读取

写入

yaml 文件内引用其他 yaml 文件的内容

读取yaml文件内的自定义函数执行结果


安装

上官网https://pyyaml.org/       

Python包 pyyaml: https://pyyaml.org/wiki/PyYAMLDocumentation

# 安装
pip install pyyaml


书写格式  YAML.rb is YAML for Ruby | Cookbook

文件名后缀:.yml

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#' 表示注释
  • YAML 流是零个或多个文档的集合。空流不包含任何文档。多个文档以 --- 分隔。
  • 时间必须使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区:2018-02-17T15:02:31+08:00
  • 数据引用: & + 数据名 定义锚点;* + 锚点名 引用锚点; <<: *锚点 合并到当前数据

隐式文档示例:

- Multimedia
- Internet
- Education

显式文档示例:

---
- Afterstep
- CTWM
- Oroborus
...

同一流中多个文档的示例:

---
- Ada
- APL
- ASP

- Assembly
- Awk
---
- Basic
---
- C
- C# # Note that comments are denoted with ' #' (space then #).
- C++
- Cold Fusion

块序列

在块上下文中,列表序列条目由 (破折号然后空格)表示:

# YAML
- The Dagger 'Narthanc'
- The Dagger 'Nimthanc'
- The Dagger 'Dethanc'
# Python
["The Dagger 'Narthanc'", "The Dagger 'Nimthanc'", "The Dagger 'Dethanc'"]

块序列可以嵌套:

# YAML
-
  - HTML
  - LaTeX
  - SGML
  - VRML
  - XML
  - YAML
-
  - BSD
  - GNU Hurd
  - Linux
# Python
[['HTML', 'LaTeX', 'SGML', 'VRML', 'XML', 'YAML'], ['BSD', 'GNU Hurd', 'Linux']]

没有必要用新行开始嵌套序列:

# YAML
- 1.1
- - 2.1
  - 2.2
- - - 3.1
  - 3.2
  - 3.3
# Python
[1.1, [2.1, 2.2], [[3.1, 3.2, 3.3]]]

块序列可以嵌套到块映射。请注意,在这种情况下,不需要缩进序列。

# YAML
left hand:
- Ring of Teleportation
- Ring of Speed

right hand:
- Ring of Resist Fire
- Ring of Resist Cold
- Ring of Resist Poison
# Python
{'right hand': ['Ring of Resist Fire', 'Ring of Resist Cold', 'Ring of Resist Poison'],
'left hand': ['Ring of Teleportation', 'Ring of Speed']}

块映射

在块上下文中,映射的键和值由:(冒号然后空格)分隔:

# YAML
base armor class: 0
base damage: [4,4]
plus to-hit: 12
plus to-dam: 16
plus to-ac: 0
# Python
{'plus to-hit': 12, 'base damage': [4, 4], 'base armor class': 0, 'plus to-ac': 0, 'plus to-dam': 16}

复杂的键用?(问号然后空格)表示:

# YAML
? !!python/tuple [0,0]
: The Hero
? !!python/tuple [0,1]
: Treasure
? !!python/tuple [1,0]
: Treasure
? !!python/tuple [1,1]
: The Dragon
# Python
{(0, 1): 'Treasure', (1, 0): 'Treasure', (0, 0): 'The Hero', (1, 1): 'The Dragon'}

块映射可以嵌套:

# YAML
hero:
  hp: 34
  sp: 8
  level: 4
orc:
  hp: 12
  sp: 0
  level: 2
# Python
{'hero': {'hp': 34, 'sp': 8, 'level': 4}, 'orc': {'hp': 12, 'sp': 0, 'level': 2}}

块映射可以嵌套在块序列中:

# YAML
- name: PyYAML
  status: 4
  license: MIT
  language: Python
- name: PySyck
  status: 5
  license: BSD
  language: Python
# Python
[{'status': 4, 'language': 'Python', 'name': 'PyYAML', 'license': 'MIT'},
{'status': 5, 'license': 'BSD', 'name': 'PySyck', 'language': 'Python'}]

流集合

YAML 中流集合的语法与 Python 中的列表和字典构造函数的语法非常接近:

# YAML
{ str: [15, 17], con: [16, 16], dex: [17, 18], wis: [16, 16], int: [10, 13], chr: [5, 8] }
# Python
{'dex': [17, 18], 'int': [10, 13], 'chr': [5, 8], 'wis': [16, 16], 'str': [15, 17], 'con': [16, 16]}

标量

YAML 中有 5 种类型的标量:普通、单引号、双引号、文字和折叠:

# YAML
plain: Scroll of Remove Curse
single-quoted: 'EASY_KNOW'
double-quoted: "?"
literal: | # Borrowed from http://www.kersbergen.com/flump/religion.html
  by hjw ___
  __ /.-.\
  / )_____________\\ Y
  /_ /=== == === === =\ _\_
  ( /)=== == === === == Y \
  `-------------------( o )
  \___/
folded: >
  It removes all ordinary curses from all equipped items.
  Heavy or permanent curses are unaffected.
# Python
{'plain': 'Scroll of Remove Curse',
'literal':
  'by hjw ___\n'
  ' __ /.-.\\\n'
  ' / )_____________\\\\ Y\n'
  ' /_ /=== == === === =\\ _\\_\n'
  '( /)=== == === === == Y \\\n'
  ' `-------------------( o )\n'
  ' \\___/\n',
'single-quoted': 'EASY_KNOW',
'double-quoted': '?',
'folded': 'It removes all ordinary curses from all equipped items. Heavy or permanent curses are unaffected.\n'}

每种风格都有自己的怪癖。普通标量不使用指示符来表示其开始和结束,因此它是最受限制的样式。它的自然应用是属性和参数的名称。

使用单引号标量,您可以表示任何不包含特殊字符的值。除了一对相邻的引号''被一个单独的单引号替换外,单引号标量不会发生转义'

双引号是最强大的样式,也是唯一可以表达任何标量值的样式。双引号标量允许转义. 使用转义序列\x*\u***,您可以表示任何 ASCII 或 Unicode 字符。

有两种块标量样式:literalfolded。文字样式最适合源代码等大块文本。折叠样式与字面样式类似,但两个相邻的非空行连接到由空格字符分隔的单行。

YAML 标签和 Python 类型

下表描述了如何将具有不同标签的节点转换为 Python 对象。

YAML 标签蟒蛇型
标准 YAML 标签
!!nullNone
!!boolbool
!!intintlongint在 Python 3 中)
!!floatfloat
!!binarystrbytes在 Python 3 中)
!!timestampdatetime.datetime
!!omap!!pairslist 对
!!setset
!!strstrunicodestr在 Python 3 中)
!!seqlist
!!mapdict
特定于 Python 的标签
!!python/noneNone
!!python/boolbool
!!python/bytesbytes在 Python 3 中)
!!python/strstrstr在 Python 3 中)
!!python/unicodeunicodestr在 Python 3 中)
!!python/intint
!!python/longlongint在 Python 3 中)
!!python/floatfloat
!!python/complexcomplex
!!python/listlist
!!python/tupletuple
!!python/dictdict
复杂的 Python 标签
!!python/name:module.namemodule.name
!!python/module:package.modulepackage.module
!!python/object:module.clsmodule.cls 实例
!!python/object/new:module.clsmodule.cls 实例
!!python/object/apply:module.f的价值 f(...)

# yaml数据为键值对格式, :后面必须留有一个空格
name: zhangsan
age: 18
# 根据缩进来判断层级目录
class:
  class_name: one
  class_no: 1
# 列表:- 后面必须留有一个空格 后面再跟数据
end:
  - id
  - index
  - list_id
  - list_index
# 注释,---为每条数据分隔符
---
name: 李四
age: 19
class:
  class_name: two
  class_no: 2
end:
  - id1
  - index1
  - list_id1
  - list_index1


# 循环遍历读取结果
{'name': 'zhangsan', 'age': 18, 'class': {'class_name': 'one', 'class_no': 1}, 'end': ['id', 'index', 'list_id', 'list_index']}
{'name': '李四', 'age': 19, 'class': {'class_name': 'two', 'class_no': 2}, 'end': ['id1', 'index1', 'list_id1', 'list_index1']}
- age: 18
  class:
    class_name: one
    class_no: 1
  end:
  - id
  - index
  - list_id
  - list_index
  name: zhangsan
- age: 19
  class:
    class_name: two
    class_no: 2
  end:
  - id1
  - index1
  - list_id1
  - list_index1
  name: "\u674E\u56DB"


# 读取结果
[{'age': 18, 'class': {'class_name': 'one', 'class_no': 1}, 'end': ['id', 'index', 'list_id', 'list_index'], 'name': 'zhangsan'}, {'age': 19, 'class': {'class_name': 'two', 'class_no': 2}, 'end': ['id1', 'index1', 'list_id1', 'list_index1'], 'name': '李四'}]


读取

读取字符串类型的yaml数据

yaml.load() 函数将YAML 文档转换为 Python 对象

import yaml


data = """
    name: zhangsan
    age: 17
    class:
        - class_one
        - class_good
        - class_nice
    """

yaml.load(data)

读取yaml格式文件

with open(yaml_path, "r", encoding="utf-8") as f:
    data = yaml.load_all(stream=f.read(), Loader=yaml.FullLoader)
f.close()


写入

import yaml


yaml.dump(data)
# 写入到文件
data_python = [
    {'name': 'zhangsan', 'age': 18, 'class': {'class_name': 'one', 'class_no': 1},
     'end': ['id', 'index', 'list_id', 'list_index']},
    {'name': '李四', 'age': 19, 'class': {'class_name': 'two', 'class_no': 2},
     'end': ['id1', 'index1', 'list_id1', 'list_index1']}
]
with open(new_yaml_file, "w", encoding="utf-8") as f:
    yaml.dump(data=data_python, stream=f)
f.close()

# 写入结果
- age: 18
  class:
    class_name: one
    class_no: 1
  end:
  - id
  - index
  - list_id
  - list_index
  name: zhangsan
- age: 19
  class:
    class_name: two
    class_no: 2
  end:
  - id1
  - index1
  - list_id1
  - list_index1
  name: "\u674E\u56DB"
# yaml.dump_all()
print(yaml.dump_all([1, 2, 3, {"name": "lisi"}]))

# 输出结果
1
--- 2
--- 3
---
name: lisi

yaml 文件内引用其他 yaml 文件的内容

临时可变参数文件 b.yml

# b.yml  存储可变参数
headers:
  Authorization: "aaaaaa_bbbbbbb"
  Host: "www.baidu.com"

body:
  appVersion: "1.0"
  logtime: 0
  userid: "100000"
  ver: "1.0"
  vercode: 1
  channel: "baidu"
# a.yml   存储全局信息,调用b.yml 中的内容
headers:
  User-Agent: "OkHttp Headers.java"
  Accept: "*/*"
  Accept-Encoding: ""
  encrypttype: "1"
  Content-Type: "application/json; charset=utf-8"
  Content-Length: "666"
  Connection: "Keep-Alive"
  Authorization: !auth b.yml
  Host: !host b.yml

body_json:
  online: "0"
  imei: ""
  mac: "A1:2C:3D:A4:A4:A0"
  platform: "1"
  net: "wifi"
  phone: "MI 9|android10"
  screen: "1080*2135"
  deviceid: "11111111111111111111111"
  androidid: "20202222222"
  appType: ""
  from: "0"
  oaid: "000000"
  ip: ""
  android_version: 29
  ua: "MI 9"
  os: "android10"
  osid: "QKQ1.190825.002"
  appVersion: !appVersion b.yml
# 添加 yaml 构造器  自定义引用方法
import yaml
import time
import os
import jsonpath
import json


def yaml_full_file(loader, node):
    """ 构造器函数。用来读取某个yaml文件内的全部内容 """
    # print(loader.name, node.value, node.tag)
    file_name = os.path.join(os.path.dirname(loader.name), node.value)  # 引用文件名
    with open(file_name, encoding="utf-8") as f:
        return yaml.load(f, Loader=yaml.FullLoader)

def yaml_value_by_appversion(loader, node, key="appVersion"):
    """ 构造器函数。用来读取某个yaml文件内指定 key 的值 """
    file_name = os.path.join(os.path.dirname(loader.name), node.value)  # 引用文件名
    with open(file_name, encoding="utf-8") as f:
        data = yaml.load(f, Loader=yaml.FullLoader)
        return jsonpath.jsonpath(data, f"$..{key}")[0]
def yaml_value_by_auth(loader, node, key="Authorization"):
    """ 构造器函数。用来读取某个yaml文件内指定 key 的值 """
    file_name = os.path.join(os.path.dirname(loader.name), node.value)  # 引用文件名
    with open(file_name, encoding="utf-8") as f:
        data = yaml.load(f, Loader=yaml.FullLoader)
        return jsonpath.jsonpath(data, f"$..{key}")[0]
def yaml_value_by_host(loader, node, key="Host"):
    """ 构造器函数。用来读取某个yaml文件内指定 key 的值 """
    file_name = os.path.join(os.path.dirname(loader.name), node.value)  # 引用文件名
    with open(file_name, encoding="utf-8") as f:
        data = yaml.load(f, Loader=yaml.FullLoader)
        return jsonpath.jsonpath(data, f"$..{key}")[0]
# 添加自定义构造器
yaml.add_constructor("!include", yaml_full_file)
yaml.add_constructor("!appVersion", yaml_value_by_appversion)
yaml.add_constructor("!auth", yaml_value_by_auth)
yaml.add_constructor("!host", yaml_value_by_host)

# 读取数据
datas = yaml.load(stream=open("./a.yml", mode="r", encoding="utf-8"), Loader=yaml.FullLoader)
# print(datas['headers'])
print(datas.get("headers"))
print(datas.get("body_json"))

 

读取yaml文件内的自定义函数执行结果

"""
读取yaml文件内有引用方法的数据,需要在另一个文件内创建需要的函数
"""
from . import custom_methods
import yaml
import os



def read_yaml(file):
    with open(file, "r", encoding="utf-8") as f:
        return yaml.load(f, Loader=yaml.FullLoader)


def get_files_name_from_path(path, suffix=".py"):
    """从指定目录下查找指定格式的文件列表"""
    for root, dirs, files in os.walk(path):
        # 循环目录返回文件名
        if len(dirs) > 0:
            for dir in dirs:
                # 递归处理目录,将结果内的文件名列表追加到列表内
                files_son = get_files_name_from_path(os.path.join(root, dir), suffix=suffix)
                files.extend(files_son)
        # 复制列表,一个列表用来循环判断,一个用来删除 (****列表删除的坑****)
        files_copy = files.copy()
        for file in files:
            if os.path.splitext(file)[-1] != suffix:
                files_copy.remove(file)
            else:
                files_copy[files_copy.index(file)] = os.path.join(root, file)
        # 返回全部文件名
        return files_copy


def auto_import_function(function_name, files):
    """从指定目录文件列表内查找指定方法,自动导包并返回方法名"""
    for file in files:
        path, filename = os.path.split(file)
        filename = os.path.splitext(filename)[0]
        if hasattr(filename, function_name):
            # exec() 方法 执行导包代码
            exec(f"from {path} import {filename}")
            return filename
    return


def str_dispose(strings):
    """ 判断一个字符串是否符合自定义方法引用规范 """
    return True if str(strings).startswith("${") and str(strings).endswith("}") else False


def variable_substitution(strings, moudule_name=custom_methods):  # 这里要写入默认值:自定义应用方法文件名
    """
    从指定py文件内查找自定义引用格式的函数方法名执行结果
    自定义方法规范:必须在指定的 moudule_name 文件内
    :param strings: 带有自定义引用的yaml字符串
    :param moudule_name: 包含自定义引用方法的文件名(不包含后缀)
    :return: 如果有则返回方法执行后的数据
    """
    name = str(strings).replace("${", "").replace("}", "")
    # 判断在指定文件内是否有定义指定函数名的方法
    if hasattr(moudule_name, name):
        # 返回该方法执行后的数据
        return getattr(moudule_name, name)()
    else:
        return


def analyze_data(data):
    """ 递归处理数据 """
    # 检查数据格式,是否是字典类型
    if isinstance(data, dict):
        for key, value in data.items():
            # 检查字典数据里的value的数据类型是否是可迭代
            if isinstance(value, (dict, list, tuple)):
                # 可迭代数据递归处理
                analyze_data(value)
            else:  # 不可迭代数据,检查是否是符合自定义函数方法引用格式
                if str_dispose(value):
                    data[key] = variable_substitution(value)
                else:  # 不处理未使用自定义函数方法引用格式的数据
                    pass
    # 检查数据格式是否可迭代
    elif isinstance(data, (list, tuple)):
        # 将可迭代数据内每一项数据进行递归处理
        for index in range(len(data)):
            data[index] = analyze_data(data[index])
    else:  # 这里处理其他类型数据
        if str_dispose(data):  # 检查是否是符合自定义函数方法引用格式
            return variable_substitution(data)
        else:  # 直接返回未使用自定义函数方法引用格式的数据
            return data
    return data


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值