xml规范_XML规范形式介绍
xml规范
XML的传统在于⽂档领域,这在其语法规则中得到了体现。 它的语法⽐与数据库记录有关的数据格式的语法宽松。 XML解析器将XML⽂档的编码形式(在XML声明中指定了编码)转换为表⽰XML⽂档中信息的抽象模型。 W3C将此抽象模型形式化为XML Infoset(请参阅),但是许多XML处理必须着重于编码的源形式,这允许⼤量的词汇差异:属性可以以任何顺序出现; 空格规则在元素名称及其属性之间的位置很灵活; 可以使⽤⼏种⽅法来表⽰字符,并转义特殊字符,等等。 命名空间引⼊了更多的词法灵活性(例如前缀选择)。 结果是,您可以拥有许多与XML 1.0规则完全等效的⽂档,⽽在按编码源进⾏逐字节⽐较时却有很⼤不同。
这种词汇上的灵活性在诸如回归测试和数字签名之类的领域中引起了问题。 假设您创建了⼀个测试套件,其中包括⼀个案例,该案例希望清单1中的⽂档为正确的输出。
清单1.⽰例XML⽂档
<doc>
<a a1="1" a2="2">123</a>
</doc>
如果进⾏适当的XML测试,您将希望将清单2中的⽂档识别为正确的输出。
清单2.清单1中的XML⽂档的等效形式
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<a
a2="2"  a1="1"
>123</a>
</doc>
标签内的空⽩不同,属性的顺序不同,并且字符实体已替换为等效的⽂字字符-但是信息集仍然相同。 通过逐字节⽐较很难建⽴这种相同性。 对于数字签名,您可能要确保通过邮件系统发送⽂档时,该⽂档在此过程中没有被损坏或篡改。 为此,您需要具有加密散列或完整的⽂档数字签名。 但是,如果您
通过消息传递系统发送 ,则可以通过正常处理看起来像 。 如果是这样,即使⽂档没有实质性更改,简单的哈希或数字签名也将不匹配。
W3C对此的解决⽅案是XML数字签名规范的⼀部分。 W3C定义了规范的XML (请参阅 ),这是XML的规范化词法形式,其中所有允许的变体都已删除,并且施加了严格的规则以允许⼀致的逐字节⽐较。 转换为规范形式的过程称为规范化 (通常缩写为“ c14n”)。 在本⽂中,您将学习XML规范形式。
规范形式的规则
c14n流程的最佳概述是规范中提供的以下列表(我已编辑):
该⽂档以UTF-8编码。
解析之前,将输⼊的换⾏符标准化为“ #xA”。
属性值被规范化,就像通过验证处理器⼀样。
默认属性被添加到每个元素,就像通过验证处理器⼀样。
CDATA节被其⽂字字符内容替换。
字符和已解析的实体引⽤将替换为⽂字字符(特殊字符除外)。
属性值和字符内容中的特殊字符被字符引⽤替换(对于格式良好的XML来说通常如此)。
XML声明和DTD被删除。 (注意:我通常建议通常使⽤XML声明,但是我赞赏以规范的XML形式省略它的背后原因。)
空元素将转换为起始标记对。
⽂档元素外部以及开始和结束标记内的空格已标准化。
保留字符内容中的所有空格(不包括换⾏归⼀化期间删除的字符)。
属性值定界符设置为引号(双引号)。
从每个元素中删除了多余的名称空间声明。
字典顺序强加于每个元素的名称空间声明和属性。
现在不要担⼼其中⼀些规则不清楚。 我将提供更详细的解释和更多更常见规则的⽰例。 在本⽂中,我不会涉及涉及DTD验证的任何c14n 步骤。 我已经多次提到XML Infoset,但是有趣的是W3C选择定义
c14n的⽅式不是根据Infoset,⽽是根据XPath数据模型,它是⽐Infoset更简单(并且有⼈认为更⼲净)的数据模型。 这可能是次要的细节,不会影响您对规范形式的⼤部分理解,但是如果您还必须使⽤基于Infoset的技术,则需要牢记这⼀点。
规范化标签
通过在标签内应⽤特定的空⽩规则以及名称空间声明和常规属性的特定顺序,可以对标签进⾏规范化。 以下是我⾃⼰的规范化开始标签格式的⾮正式序列:
1. 尖括号(<),后跟元素QName(前缀,冒号和本地名称)。
2. 默认的名称空间声明(如果有),然后是所有其他名称空间声明,按照它们定义的前缀的字母顺序排列。 省略所有冗余的名称空间声
明(那些已在祖先元素中声明但未被覆盖的名称空间)。 在每个名称空间声明之前,请使⽤单个空格,在等号的两侧都不能使⽤空格,并在名称空间URI周围使⽤双引号。
3. 所有按字母顺序排列的属性,其前都有⼀个空格,等号的两边都没有空格,并在属性值两边加上双引号。
4. 最后,⽤尖括号(>)。
规范的结束标签要简单得多:尖括号(<)后跟元素QName,然后尖括号(>)。 清单3是⾮规范形式的XML⽰例。
清单3.⾮规范形式的XML样本
<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:x="example/x" xmlns="example/default">
<a
a2="2"  a1="1"
>123</a>
<b y:a1='1' xmlns="example/default" a3='"3"'
xmlns:y='example/y' y:a2='2'/>
</doc>
清单4是规范形式的同⼀⽂档。
清单4.清单3为规范的XML
<doc xmlns="example/default" xmlns:x="example/x">
<a a1="1" a2="2">123</a>
<b xmlns:y="example/y" a3=""3"" y:a1="1" y:a2="2"></b>
</doc>
为了规范化需要进⾏以下更改:
删除XML声明(该⽂档已经在UTF-8中,因此⽆需进⾏转换)。
将默认名称空间声明放在doc之前,再声明其他任何名称空间(在本例中为前缀x )。
减少内部的空⽩a开始标记,以便有每个属性前⼀个空格。
删除b开始标记上的冗余默认名称空间声明。
确保其余的名称空间声明(⽤于y前缀)位于所有其他属性之前。
将其余属性按其QName的字母顺序排列(例如,“ a3”然后“ y:a1”然后“ y:a2”)。
将xmlns:y命名空间声明和y:a1 , y:a2和a3属性上的引号定界符从单引号( ' )更改为双引号( " ),这在a3的情况下还要求嵌⼊的双引号⽤引号( " )换成" 。
我测试使⽤Python中C14N模块,附带的PyXML(见规范形式转换 )。 清单5是我⽤来规范化到的代码。
清单5.⽤于规范化XML的Python代码
from xml.dom import minidom
python处理xml文件from import c14n
doc = minidom.parse('l')
canonical_xml = c14n.Canonicalize(doc)
print canonical_xml
规范化字符数据
规范形式的字符数据基本上是尽可能的原义:字符实体解析为原始Unicode(然后将其序列化为UTF-8)。 CDATA节被其原始内容替换;以及沿着这些思路的更多变化。 这对于属性值和内容中的字符数据都是如此。 属性也根据其DTD类型的规则进⾏规范化,但这在很⼤程度上影响了使⽤DTD的⽂档,在本⽂中我不会介绍。 清单6是⼀个⽰例⽂档,部分基于c14n规范中的⽰例。
清单6.⽤于演⽰字符数据规范化的⽰例XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<doc>
<text>First line Second line</text>
<value>2</value>
<compute><![CDATA[value>"0" && value<"10" ?"valid":"error"]]></compute>
<compute expr='value>"0" && value<"10" ?"valid":"error"'>valid</compute>
</doc>
是规范形式的同⼀⽂档。
为了规范化需要进⾏以下更改:
删除XML声明并转换为UTF-8。
更改字符引⽤2 到实际数字2。
⽤其内容替换CDATA部分,并⽤>;转义右尖括号(>) > ,与& ,并且带有<;尖括号(<) < 。
⽤双引号替换⽤于expr属性的单引号,然后将双引号( " )字符转义为"" 。
我在清单和中没有提到的重要步骤是转换为UTF-8,这在⽂章清单中不容易说明。 假设源⽂档的字符引⽤为© (代表版权标志)。 规范形式将其替换为UTF-8序列,该序列包括⼗六进制字节C2和⼗六进制字节A9。
不要忘记独家选项
有时您实际上是想签名或⽐较XML⽂档的⼦树,⽽不是整个。 也许您只想签名SOAP消息的主体,⽽忽略信封。 W3C在专有规范格式规范中对此进⾏了规定,该规范⼏乎完全与整理⽬标⼦树内外的名称空间声明有关。
我提到了由前缀选择引起的潜在差异。 XML命名空间规定前缀是⽆关紧要的,因此两个仅在命名空间前缀选择上不同的⽂件应被视为相同。 不幸的是,c14n⽆法解决这种情况。 ⼀些完全有效的XML处理操作可能会修改前缀,因此请注意这⼀潜在问题。
规范XML是掌握的重要⼯具。 您可能不会⽴即参与与XML相关的安全性或软件测试,但是⼀旦熟悉c14n就会经常出现,这会让您感到惊讶。 这是可以帮助您避免很多⼀开始可能会遇到的⿇烦的事情之⼀。
翻译⾃:
xml规范

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。