【拓展知识】xmlschema 和 jsonschema的语法
schema (XSD)
XML Schema 描述 XML 文档的结构。可以指定一个.xsd (xml schema) 验证某个xml
作用:定义 XML 文档的合法构建模块,类似 DTD(文档类型定义)
参考地址: https://www.w3school.com.cn/schema/index.asp
xml 了解: https://www.cnblogs.com/phoenixy/p/15839462.html
声明
<!-- xs:schema 根元素 包含属性声明--> <!-- xmlns:xs 规定元素和数据类型取自命名空间 http://xxx 且使用前缀 xs: --> <!-- targetNamespace 元素取自命名空间 http://xxx --> <!-- elementFormDefault 元素必须被命名空间限定 --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3school.com.cn" xmlns="http://www.w3school.com.cn" elementFormDefault="qualified" > <!--简易元素--> <xs:element name="name" type="xs:string"/> </xs:schema>
数据类型
拓展
属性
<!-- xs:schema 根元素 包含属性声明--> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" > <!-- attribution 属性定义 use规定属性是必须的 --> <xs:attribution name = "attr" type="xs:string" use="required"/> <!-- 带有属性 attr 的元素 --> <name attr="EN">lucy</name> </xs:schema>
简易元素
只有元素本身,不包含其他元素
<!-- 语法 xxx 指元素的名称,yyy 指元素的数据类型 -->
<!-- default 缺省值--> <xs:element name="xxx" type="yyy" default="name"/> <!--fixed 固定值--> <xs:element name="color" type="xs:string" fixed="name"/>
限定
取值范围限定
<!-- 带有限定的元素 age --> <xs:element name="age"> <!-- 简易类型 --> <xs:simpleType> <!-- 元素限定 取值范围 在18-60之间 --> <xs:restriction base="xs:integer"> <!-- minInclusive 最小范围(包含); minExclusive 最小范围(不包含) --> <xs:minInclusive value="18"/> <!-- maxInclusive 最大范围(包含); maxExclusive 最大范围(不包含) --> <xs:maxInclusive value="60"/> <!-- 限定结束 --> </xs:restriction> <!-- 简易类型结束 --> </xs:simpleType> <!-- 元素结束 --> <xs:element/>
枚举限定
<xs:element name="idName"> <!-- 简易类型 --> <xs:simpleType> <!-- 元素限定 枚举 --> <xs:restriction base="xs:string"> <!-- enumeration 枚举约束 在zhangsan、lisi、wangwu中 --> <xs:enumeration value="zhangsan"/> <xs:enumeration value="lisi"/> <xs:enumeration value="wangwu"/> </xs:restriction> </xs:simpleType> </xs:element>
模式限定
<xs:element name="enName"> <!-- 简易类型 --> <xs:simpleType> <!-- 元素限定 正则 --> <xs:restriction base="xs:string"> <!-- pattern 模式约束 三个a-z的数据且首字母大写 --> <xs:pattern value="[A-Z][a-z][a-z]"/> <!-- pattern 模式约束 5个阿拉伯数字 --> <xs:pattern value="[0-9][0-9][0-9][0-9][0-9]"/> <!-- pattern 模式约束 xyz中的一个 --> <xs:pattern value="[xyz]"/> <!-- pattern 模式约束 a-z中的0个或多个 --> <xs:pattern value="([a-z])*"/> <!-- pattern 模式约束 一对数据且一个小写一个大写 --> <xs:pattern value="([a-z][A-Z])+"/> <!-- pattern 模式约束 men或者women --> <xs:pattern value="men|women"/> <!-- pattern 模式约束 8个在 a-zA-Z0-9 范围内的数据 --> <xs:pattern value="[a-zA-Z0-9]{8}"/> </xs:restriction> </xs:simpleType> </xs:element>
空白字符限定
<xs:element name="addr"> <!-- 简易类型 --> <xs:simpleType> <!-- 元素限定 空白字符 --> <xs:restriction base="xs:string"> <!-- whiteSpace 不移除空白字符 --> <xs:whiteSpace value="preserve"/> <!-- whiteSpace 移除空白字符(包括换行、回车、空格以及制表符) --> <xs:whiteSpace value="replace"/> <!-- whiteSpace 去除开头结尾的空格,且换行、回车、空格以及制表符及连续空格会替换为单个空格 --> <xs:whiteSpace value="collapse"/> </xs:restriction> </xs:simpleType>
</xs:element>
长度限定
<xs:element name="phone"> <!-- 简易类型 --> <xs:simpleType> <!-- 元素限定 长度限定 --> <xs:restriction base="xs:string"> <!-- length 精确到11位字符 --> <xs::length value="11"/> <!-- minLength 最小7位字符,maxLength 最长11位字符 --> <xs:minLength value="7"/> <xs:maxLength value="11"/> </xs:restriction> </xs:simpleType> </xs:element>
<xs:element name="score"> <!-- 简易类型 --> <xs:simpleType> <!-- 元素限定 精确位数限定 --> <xs:restriction base="xs:string"> <!-- totalDigits 允许总位数 --> <xs::length value="8"/> <!-- fractionDigits 小数位数 --> <xs:fractionDigits value="2"/> </xs:restriction> </xs:simpleType> </xs:element>
复合元素
<!-- xs:schema 根元素 包含属性声明--> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" > <xs:element name="Name"> <!-- 复合元素 --> <xs:complexType> <xs:sequence> <xs:element name="idName" type="xs:string"/> <xs:element name="custName" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element> <!-- 根元素结束 --> </xs:schema>
数据类型限定
Order指示器
<!-- 复合元素 --> <xs:complexType> <!-- 任意顺序出现 --> <xs:all> <xs:element name="idName" type="xs:string"/> <xs:element name="custName" type="xs:string"/> </xs:all>
</xs:complexType>
<!-- 选择出现 --> <xs:Choice > <xs:element name="idName" type="xs:string"/> <xs:element name="custName" type="xs:string"/> </xs:Choice >
<!-- 按顺序出现 --> <xs:sequence> <xs:element name="idName" type="xs:string"/> <xs:element name="custName" type="xs:string"/> </xs:sequence>
<!--XMLSchema 根元素 包含属性声明;地址是schema用到的元素和数据类型来自命名空间 使用前缀xs:--> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!--复合元素--> <xs:element name="response"> <xs:complexType> <xs:all maxOccurs="1"> <xs:element name="content" type="xs:string"/> <xs:element name="respCode" minOccurs="0"> <xs:simpleType> <xs:restriction base="xs:string"> <!--处理成功--> <xs:enumeration value="0000"/> <!--业务处理异常--> <xs:enumeration value="9999"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="respMsg" type="xs:string"/> </xs:all> </xs:complexType> </xs:element> </xs:schema>
jsonschema
Json Schema 描述 Josn 文档的结构。
官方版本参考: https://json-schema.org/specification-links.html
jsonschema参考地址:https://www.freesion.com/article/7617866008/
jsonschema 组成结构
声明版本
# $schema 声明了针对该架构编写的JSON Schema标准版本 "$schema": "http://json-schema.org/draft-04/schema#",
文档标题
# title 文档标题,关键字是描述性的,用来对文档作补充说明 "title": "respMsg schema",
文档描述
# description 文档描述,关键字是描述性的,用来对文档作补充说明 "description": "validate result information",
字段描述
# default 描述字段 非必须字段 # "default":{} "default": "描述字段" "example": "描述字段(in draft 6),用于展示转换前的json; " $comment: "描述字段(in draft 7 用于 schema 开发人员对文档进行注释,不需要展示给最终用户看。)"
{ // 声明 "$schema": "http://json-schema.org/draft-04/schema#", // 标题 "title":"Message", // 描述 "description":"validata information", }
type类型
Object 对象
{ // 声明 "$schema": "http://json-schema.org/draft-04/schema#", // 标题 "title":"Message", // 描述 "description":"validata information", // 类型 对象object "type":"object", //additionalProperties 默认true(允许properties之外的属性存在); false(不可以出现properties之外的属性) "additionalProperties":false, // required 存放必要属性列表 "required":["respCode", "respMsg"] // object 出现的属性字段 "properties":{
// string 字符串 "respCode":{"type": "string"} "respMsg":{"type": "string"} "failMsg":{"type": "string"} } // 属性数量最小值 "minProperties":2 // 属性数量最大值 "maxProperties":2 // dependencies 定义属性依赖值 "dependencies":{ // failMsg依赖于respMsg,当resoMsg存在时,failMsg才必须存在 "failMsg":["respMsg"] } }
array 数组
{ // 类型 数组 array "type":"array", // additionalItems默认true(允许items之外的项目存在); false(不可以出现items之外的项目) "additionalItems":false, // 针对数组中的所有元素类型进行验证,当数组中存在类型非string时。整个数组无效 (慎用) // "contains": {"type":"string"}, // 验证数组中的所有元素的类型;每个元素都可以具有不同的类型,列表验证(任意长度的序列)和元组验证(固定长度的序列) "items":{ // string 字符串 "respCode":{"type": "string"} "respMsg":{"type": "string"} "failMsg":{"type": "string"} } // 非负数最小长度 "minItems":2 // 非负数最大长度 "maxItems":2 // 数组内元素唯一性验证 True 不能有重复元素 "uniqueItems": false }
String 字符串
{ // 类型 字符串 string "type":"string", // 字符串最大长度(包含) "maxLength":3, // 字符串最小长度(包含) "minLength":1, // 正则匹配字符串 示例:(xxx)xxx-xxxx x代表0-9的数字 pattern 验证固定电话,pattern_date 验证日期格式 yyyyMMdd "pattern":"^(([0-9]{3}))?[0-9]{3}-[0-9]{4}$"
"pattern_date":"((^((1[8-9][0-9]{2})|([2-9][0-9]{3}))(10|12|0?[13578])(3[01]|[12][0-9]|0?[1-9])$)|(^((1[8-9][0-9]{2})|([2-9][0-9]{3}))(11|0?[469])(30|[12][0-9]|0?[1-9])$)|(^((1[8-9][0-9]{2})|([2-9][0-9]{3}))(0?2)(2[0-8]|1[0-9]|0?[1-9])$)|(^([2468][048]00)(0?2)(29)$)|(^([3579][26]00)(0?2)(29)$)|(^([1][89][0][48])(0?2)(29)$)|(^([2-9][0-9][0][48])(0?2)(29)$)|(^([1][89][2468][048])(0?2)(29)$)|(^([2-9][0-9][2468][048])(0?2)(29)$)|(^([1][89][13579][26])(0?2)(29)$)|(^([2-9][0-9][13579][26])(0?2)(29)$))"
// 指定MIME类型的字符串的内容 示例:包含一个HTML文档 // "contentMediaType":"text/html", // 指定的编码用于存储内容 示例:使用Base64编码的PNG图像 "contentEncoding":"base64", "contentMediaType":"image/png" }
number 数值(任何数字类型,整型或浮点型都可)
{ // 类型 数值 number "type":"number", // 倍数 1的倍数 取值必须是大于0的整数 // "multipleOf":1, // 最小值(包含) "minimum":1, // boolean不包含最小值 或 数值 开区间最小值 "exclusiveMinimum":true, //最大值(包含) "maximum":999.99, // boolean不包含最大值 或 数值 开区间最大值 "exclusiveMaximum":true
}
integer 整型 (同number)
{ // 类型整型 "type":"integer", // 倍数 1的倍数 取值必须是大于0的整数 // "multipleOf":1, // 最小值(包含) "minimum":1, // 不包含最小值 "exclusiveMinimum":true, //最大值(包含) "maximum":999.99, // 不包含最大值 "exclusiveMaximum":true }
boolean 布尔值
仅包含true和false
null 空值
仅支持字段值为null
any 任何值
支持所有类型
const 关键字验证
验证值必须等于该常量,此关键字的值可以是任何类型,包括null。
enum 枚举值
值只能是enum数组中的某一项 示例:["a", "b"]
多类型
判断 "if":{},"then":{},"else":{}
{ "$schema": "http://json-schema.org/draft-04/schema#", "title":"Message", "description":"validata information", "type":"object", "properties":{ "name":{ "type":"string", }, "sex":{ "enum":["man", "woman"] } }, // 条件 "if":{ "properties":{"age":{"const":"man"}} }, // 符合条件 stage值 "then":{ "properties":{"stage":{"enum":["男"]}} }, // 不符合条件 stage值 "else":{ "properties":{"stage":{"enum":["女"]}} } }
验证schema
jsonSchema 校验
def resp_json_check(self, data, cmd): json_schema_pathname = os.path.dirname(os.getcwd()) + "\\schema\\schema_%s.json" % cmd try: with open(json_schema_pathname, 'r', encoding='utf-8') as f: json_doc = commentjson.loads(f.read()) except Exception as e: logs.warning("未进行数据规则校验,发生异常原因:" + str(e) + "[请前往目录检查文件]") return False else: try: # validate校验, 跟assert断言一个意思 validate(instance=eval(data), schema=json_doc, format_checker=draft7_format_checker) except SchemaError as e: logs.error("SchemaError:数据不符合规则,请检查数据or修改校验文件") error1 = "验证模式schema出错:\n出错位置:{}\n提示信息:{}".format(" →".join([str(i) for i in e.path]), e.message) logs.error(error1) return error1 except ValidationError as e: logs.error("ValidationError:数据不符合规则,请检查数据or修改校验文件") error2 = "验证模式schema出错:\n出错位置:{}\n提示信息:{}".format(" → ".join([str(i) for i in e.path]), e.message) logs.error(error2) return error2 else: logs.info("基础校验 --> schema校验符合规则,验证通过!") return True
xmlschema 校验
def resp_xsd_check(self, data): xml_doc = data xsd_schema_path = os.path.dirname(os.getcwd()) + "\\schema\\resp_xsd_check.xsd" try: with open(xsd_schema_path,encoding='utf-8') as f: xsd_doc = f.read() except Exception as e: logs.warning("未进行 xsd 数据规则校验,发生异常原因:" + str(e) + "[请前往目录检查文件]") return False else: xsd_doc_io = StringIO(xsd_doc) xsdCheck_doc = etree.parse(xsd_doc_io) xml_doc_io = StringIO(xml_doc) xmlschema = etree.XMLSchema(xsdCheck_doc) xmlCheck_doc = etree.parse(xml_doc_io) try: xmlschema.validate(xmlCheck_doc) xmlschema.assertValid(xmlCheck_doc) except lxml.etree.XMLSchemaParseError as xspe: logs.warning("XMLSchemaParseError occurred!" + str(xspe)) return False except lxml.etree.XMLSyntaxError as xse: logs.warning("XMLSyntaxError occurred!" + str(xse)) return False except lxml.etree.DocumentInvalid: logs.warning("xsd 数据不符合规则,请检查数据or完善文件") error = xmlschema.error_log.last_error if error: logs.error("异常原因:" + error.message) return False else: return True else: logs.info("xsd 数据符合规则,验证通过!") return True
拓展
1、UnicodeDecodeError:: 'utf-8' codec can't decode byte 0xc8 in position 0: invalid contin
出现场景:读取json文件时报错
问题原因:字符编码问题
ASCII
编码:大小写英文字母、数字和一些符号
GB2312编码:收录汉字6763个,采用双字节编码。
GBK编码:收录汉字21003个,采用双字节编码。
GB18030编码:目前收录汉字70000余个,以及多种少数民族文字。采用单字节、双字节、四字节分段编码。
Unicode编码:所有语言都统一到一套编码里,采用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。
ASCII与Unicde转化:ASCII编码的数据用Unicode编码,只需要在前面补0就可以。
bytes
类型的数据用带b
前缀的单引号或双引号表示
解决方法:将json文件转换为需要读取的编码(utf-8)模式(Notepad++ 设置 - 编码 - 使用utf-8编码)
2、
// boolean不包含最大值 或 数值 开区间最大值 "exclusiveMaximum":true
如果万事开头难 那请结局一定圆满 @ Phoenixy
-------------------------------------------------------------------------------------