1 数据传输编码
1.1 编码协议对比
总所周知,在计算机通信协议中存在多种数据传输和表达方法。例如Http通信使用了XML作为数据传输载体,在MQTT、WebSocket、Http(RESTful 架构)中都使用了JSON作为数据载体,在微服务架构、物联网与边缘计算、游戏与实时通信中常常使用Protobuf数据格式。这些数据格式面对不同的应用范围表现出了各自的特点。
ISO 15118是一套车与桩之间的通信协议,使用EXI编码作为数据传输载体,属于强制型国际标准。
EXI(Efficient XML Interchange)是W3C标准化的高效XML交换格式,特点是通过二进制编码大幅压缩XML数据体积,同时提升解析速度并降低内存、功耗等资源消耗,适合应用在资源受限的嵌入式系统、物联网设备及标准化工业协议(如V2G充电)领域。
下面是对XML、JSON、Protobuf、EXI四种编码协议和特点对比:
特性
|
XML
|
JSON
|
Protobuf
|
EXI
|
可读性
|
高(文本格式,标签自描述)
|
高(文本格式,键值对结构)
|
低(二进制格式,需解析工具)
|
低(二进制压缩XML,需模式支持)
|
数据体积
|
最大(冗余标签导致膨胀)
|
中等(无冗余标签,但保留格式字符)
|
最小(二进制紧凑编码,体积为XML的1/20)
|
极小(压缩率可达XML的1/100,需模式优化)
|
序列化/反序列化速度
|
慢(解析需DOM/SAX,资源消耗高)
|
中等(文本解析效率低于二进制)
|
最快(二进制直接映射内存,速度比JSON快10-20倍)
|
快(二进制流处理,速度接近Protobuf)
|
跨语言支持
|
广泛(几乎所有语言支持)
|
全面(原生支持JavaScript,其他语言库丰富)
|
高(需预生成代码,支持多语言)
|
中(依赖模式定义,需特定编解码库)
|
适用场景
|
复杂数据结构、文档交换(如Web服务配置)
|
Web API、前后端交互(轻量级数据交换)
|
高性能通信(如微服务、物联网设备)
|
嵌入式系统、电力线通信(如ISO 15118充电协议)
|
扩展性
|
高(自定义标签和命名空间)
|
中(结构固定,嵌套层级有限)
|
中(需预定义.proto文件,支持向后兼容)
|
低(需严格模式定义,动态扩展受限)
|
典型工具/库
|
DOM解析器、XPath
|
FastJSON、Gson、cJson
|
Google Protocol Buffers编译器
|
W3C EXI编码库、模式生成工具
|
性能排序:Protobuf ≈ EXI > JSON > XML
可读性排序:XML > JSON > EXI > Protobuf
【关键结论】
-
性能与体积:Protobuf和EXI在传输效率和存储空间上显著优于XML/JSON,Protobuf适合通用高性能场景,EXI针对XML场景优化(如充电桩通信)。
-
开发便利性:JSON凭借简洁语法和广泛支持,仍是Web开发的首选,而Protobuf需额外编译步骤。
-
可维护性:XML/JSON的可读性优势在调试阶段更为重要,Protobuf/EXI则需依赖工具链解析。
-
行业适配:物联网和边缘计算倾向于Protobuf/EXI以降低带宽消耗,传统企业系统仍依赖XML/JSON的兼容性
1.2 XML和EXI相互结合的特点
在ISO 15118协议中规定了通信命令数据结构、类型,发布了一整套xsd规范,要求通信命令必须遵守xsd规范,强制使用EXI编码。作者认为这样就把XML和EXI两者结合起来,发挥了各自的优势,克服了各自的缺点,在EV充电应用场景中更加适合不同汽车厂家、充电桩厂家之间设备互联互通,达到通用化、标准化的目的,确实是一套比较理想的编码方案。
XML的技术优势与局限性:
优势
|
局限性
|
结构化数据支持复杂业务场景
|
数据冗余度高,传输效率低
|
自描述性降低解析复杂度
|
解析速度较慢,对资源消耗较大
|
扩展性强,兼容新旧系统
|
语法严格,容错性差
|
XML最大的缺点就是数据冗余、解析速度慢,消耗资源大,但是在EXI加持下刚好弥补了这个缺点。EXI数据精简,编解码速度飞快,资源消耗极少。这套XML+EXI方案非常适合复杂的命令数据,唯一的缺点是需要专门的编解码库, 本章将重点介绍EXI编码原理和实现方案。
2 EXI协议原理
EXI协议下载:
本章节主要来自于[简明原理],目的是简明扼要的介绍EXI编码结构和过程,帮助读者快速了解EXI协议概念。对于编码方案的更多细节需要读者自行阅读[完整规范]。本文还会针对核心内容添加了作者自己的研究经验。
2.1 EXI概念
高效XML交换(Efficient XML Interchange, EXI)格式是一种非常紧凑、高性能的XML表示,旨在为广泛的应用程序提供良好的工作环境。它同时提高了性能并显著降低了带宽需求,而不会影响电池寿命、代码大小、处理能力和内存等其他资源的有效使用。
EXI使用语法驱动的方法,使用简单的编码算法和一小组数据类型表示实现非常有效的编码。因此,EXI处理器相对简单,可以在容量有限的设备上实现。
EXI是模式“知情的”,这意味着它可以利用可用的模式信息来提高紧凑性和性能,但不依赖于准确、完整或当前的模式来工作。它支持任意模式扩展和偏差,并且在部分模式或没有模式的情况下也能非常有效地工作。格式本身也不依赖于模式信息的任何特定模式语言或格式。
一个被称为EXI处理器的程序模块,无论是软件还是硬件,都被应用程序用来将它们的结构化数据编码成EXI流和/或解码EXI流以使结构化数据可访问。前面提到的EXI处理器的前一种和后一种角色分别称为EXI流编码器和EXI流解码器。该文档不仅指定了EXI格式,而且还定义了需要EXI处理器检测和处理的错误。
2.2 EXI码流格式
EXI 将 XML 文档的内容表示为 EXI 流,EXI 流由 EXI 头部和 EXI 正文组成,如下表1所示。
表2-1. EXI流结构
EXI Header
|
EXI Body
|
EXI 头部传递格式版本信息,并且可能还包括在编码过程中使用的选项集。如果这些选项被省略,编解码过程中就假定解码器可以通过带外机制访问这些选项。EXI 正文由描述被编码的文档(或文档片段)的事件序列组成。
2.2.1 EXI 头部
EXI 头部传达了解码 EXI 正文所需的编码属性。最小的头部可以用一个字节表示,这样可以将开销和复杂度降到最低,并且不会牺牲紧凑性,特别是对于小文档来说,头部可能会引入较大的常数因子。
EXI 头部的结构如下图所示:
表2-3. EXIt 头部结构
[EXI Cookie]
|
Distinguishing Bits
|
Presence Bit for EXI Options
|
EXI Format Version
|
[EXI Options]
|
[Padding Bits]
|
EXI 头部以可选的四字节 EXI Cookie 开始。四字节字段由四个字符 " $ "、" E "、" X " 和 " I " 组成,按此顺序排列,每个字符都表示为一个 ASCII 八位字节,这可以用来区分 EXI 流与其他数据流。
EXI Cookie 后面跟着一对区分位。这个二进制序列(1 0)可以用来区分 EXI 文档和文本 XML 文档,并且足以基于广泛的字符编码区分 EXI 流和 XML 流。
EXI 选项存在位紧跟在区分位之后。该位的值用于指示是否存在 EXI 选项,这些选项稍后会出现在头部中。
EXI 格式版本标识正在使用的 EXI 版本,并允许未来的改进和修改。前导的 0(零)位表示文档是根据最终版本的推荐编码的,而前导的 1(一个)位表示这是预览版本。引入这种区分是为了方便早期发布预览版本,这些版本的互操作性要求较低。只有最终版本才要求被符合要求的处理器处理。前导位后跟一个或多个 4 位序列,整体解释为从 1 开始的格式版本号。例如,4 位序列 0000 被解释为版本 1,两个 4 位序列 1111 0001 被解释为版本 17。

EXI 选项指定了如何编码 EXI 流的正文,正如前面所述,它们的存在由头部中的存在位控制。由于 EXI 选项是通过 XML Schema 正式描述的,并且也是使用 EXI 编码的,因此它们引入的开销相对较小。下表描述了可以在 EXI 头部中指定的 EXI 选项。当 EXI 选项文档没有为某个特定选项指定值时,假定使用默认值。
表2-4.EXI 选项

大多数选项都是直接的,作为布尔值启用或禁用某个功能。它们通过可选的 XML 元素表示,并且也通过 EXI 编码。关于用于编码这些选项的 XML Schema 的更多信息,请参见 EXI 选项头部的 XML Schema。
上表中的 preserve 选项实际上是一组选项,控制哪些 XML 项目被保留,哪些 XML 项目被忽略。它们统称为保真度选项。可以使用这些选项来消除传输未使用的 XML 项目所带来的开销。某些 XML 项目,如处理指令或 DTD(文档类型定义),可能永远不会出现(例如,在 SOAP 中),或者对用例或应用程序领域来说根本不重要。保真度选项用于管理某些 XML 项目的过滤器,具体如以下表所示。自然地,编码时丢弃的 XML 项目(由于保真度选项的特定设置)在解码时无法精确恢复。
表2-5.EXI 保真度选项

2.2.2 EXI 正文
EXI 文档的正文由一系列 EXI 事件组成。XML 项目被编码为一个或多个 EXI 事件;例如,名为 foo 的属性可以编码为 AT("foo"),而名为 bar 的元素可以编码为一对事件:SE("bar") 和 EE。EXI 事件可能具有与其相关联的附加内容。例如,属性事件 AT("foo") 可能与值 foo1 关联。下表展示了所有可能的事件类型及其与结构和内容相关的项。在 EXI 术语中,内容指的是属性和值,而所有其他信息项被视为属于结构类别。
表 2-6. EXI 事件类型

对于命名的 XML 项目,如元素和属性,存在三种类型的事件:SE(qname)、SE(uri:*) 和 SE(*),以及 AT(qname)、AT(uri:*) 和 AT(*)。这些事件在其相关联的结构上有所不同:当使用 SE(qname) 或 AT(qname) 时,XML 项目的实际 qname 不会作为事件的一部分进行编码,而 SE(uri:*) 和 AT(uri:*) 事件则不会编码 uri。选择使用哪种类型的事件将在引入 EXI 语法的概念后进行解释。此外,保真度选项可能允许保留命名空间前缀。
在2.2.1节中介绍的EXI报头的保真度选项可用于修剪EXI事件,如命名空间声明(NS),注释(CM),处理指令(PI), DOCTYPE (DT)或实体引用(ER)。语法修剪简化了编码和解码过程,并通过过滤掉未使用的事件类型提高了紧凑性。
考虑一个来自笔记本应用程序的简单XML文档,作者将这个XML文档为例详细说明是如何编码的。
Example 2-1. Notebook (XML Document)
<?xml version="1.0" encoding="UTF-8"?>
<notebook date="2007-09-12">
<note category="EXI" date="2007-07-23">
<subject>EXI</subject>
<body>Do not forget it!</body>
</note>
<note date="2007-09-12">
<subject>Shopping List</subject>
<body>milk, honey</body>
</note>
</notebook>
与此XML文档主体对应的EXI事件序列如下所示:
Figure 2-1. EXI Body Stream

这个EXI事件序列可以很容易地映射到上面所示的XML文档的结构。每个文档都以开始文档(SD)开始,以结束文档(ED)结束。在无模式(
schema-less)和有模式(
schema-informed)的EXI流中,属性编码的顺序可能不同,与每个事件关联的确切内容也是如此。用于表示每种事件类型(不包括其内容)的实际位数因上下文而异。在特定上下文中可以发生的事件类型越多,表示该上下文中事件所需的位数就越大。在这种情况下,上下文的构成由下一节中的EXI语法产物更正式地定义。
2.2.3 EXI 语法
EXI是一种基于知识的编码,它使用一组语法来确定在EXI流的任何给定点上最有可能发生哪些事件,并用更少的比特对最有可能的替代事件进行编码。它通过将事件流映射到一组较低熵的代表性值,并使用一组简单的变长代码或EXI压缩算法对这些值进行编码来实现这一点。
EXI语法是规则语法,其结果与事件代码相关联。由XML事件流驱动的EXI编码器将事件与语法结果相匹配,并使用它们相关的事件代码来表示XML文档或XML片段。由于EXI语法是规则语法,编码器编写的事件代码序列对应于接受该语法的有限自动机中的路径。实际上,由于XML不是一种规则语言,因此不能使用单一语法来表示整个XML事件流。相反,EXI编码器使用一堆语法,每个元素内容模型一个语法(就像XML Schema验证器可能做的那样)。
事件代码由一到三个部分组成的序列表示,其中每个部分都是一个非负整数。EXI语法中的事件代码以这样一种方式分配给产品,即使用较短的事件代码来表示更有可能发生的产品。相反,较长的事件代码用于表示不太可能发生的结果。EXI语法的设计方式是,表示每个结果所需的平均位数少于不区分更可能和更不可能结果的语法。下表通过一个示例说明了这一原则。

在第一个表中,结果没有根据它们的概率分开,需要一个4位代码来表示每个条目。另一方面,在第二个表中,代码长度从2位到6位不等,因为结果是根据它们发生的可能性进行分组的。很明显,发生概率越高的事件编码长度越短,发生概率越低的事件编码长度越长。假设被编码的元素的内容模型对应于序列AT(类别)AT(日期)(即,元素声明了两个属性),那么使用第一个表,所有事件代码的编码总长度是4x2=8位;使用第二个表,所有事件代码的编码总长度是2x2=4位,这就说明使用第二个表编码长度将缩短4位。
EXI语法利用了对所编码数据类型的先验知识,即XML文档和XML片段。特别是,EXI语法可以利用这样一个事实,即在任何给定的语法上,某些XML项比其他项更受欢迎。例如,通过对真实文档的简单检查,很容易验证属性是否比处理指令出现得更频繁,因此应该接收更短的事件代码。如果模式信息可用,则可以进一步改进语法设计。
在这种情况下,我们不仅可以利用通用的XML知识,还可以利用特定于被编码的文档类型的知识。例如,如上表所示,我们可以用比AT(*)更短的事件代码添加特定的产品,如AT(类别)和AT(日期)。
下面两个部分将描述内置语法和基于模式的语法之间的区别。请注意,EXI编码器可能只有部分模式(
schema)信息,在这种情况下,它将在编码期间使用内置语法和模式通知语法的组合。
2.2.3.1 内置语法
当没有可用的模式信息时,EXI使用一组内置语法对XML文档和XML片段进行编码。由内置语法对文档、片段和元素进行编码。文档语法和片段语法描述顶层结构,而元素语法描述每个元素的结构。片段语法比文档语法更宽松;例如,它们允许将多个顶级元素编码为兄弟元素。有关这些语法的更多信息,请参阅内置XML语法。
EXI格式描述了一种机制,通过该机制,使用来自被编码的实际实例的信息动态扩展内置语法。换句话说,EXI格式描述了一种学习机制,可以在没有静态模式信息可用时进一步提高效率。新学习的产品被分配了短事件代码,提高了这些产品的每次后续使用的紧凑性。此外,通过向语法中添加新的结果,与事件关联的某些数据只需要编码一次。例如,如果一个名为notebook的元素由SE(*)匹配,随后又由SE(notebook)匹配,那么实际的localName“notebook”只作为SE(*)事件的一部分编码一次。
正如前一节所指出的,EXI语法总是规则的,因此可以被有限自动机(FA)接受。为了提供一个更具操作性的EXI处理器视图,我们将选择使用FA来解释语法的工作原理。下图显示了一组语法,其中顶层语法接受“note”元素。黑色的状态转换对应于内置的元素语法;红色的状态转换是之前对元素进行编码的结果。

Figure 2-2.
Built-In Grammar for SE(note)
内置的元素自动机有两个不同的状态:StartTag和Element。前者接受必须发生在任何元素内容之前的属性和名称空间事件;后者只接受元素内容,不包括属性和名称空间事件。这种分离允许使用短代码,从而提高了紧凑性和处理时间。
如前所述,红色的转换是对内置元素语法的扩展,该语法基于获得的关于元素[note]的知识。注意AT(date)、AT(category)和SE(subject)是如何从StartTag状态中添加出来的,而SE(subject)是如何从Element状态中添加出来的。特别是,这表明SE(subject)预计会发生在SE(body)之前,并且这两个SE事件都预计会发生在任何AT事件之后。此外,请注意AT(*)和SE(*)仍然可用,以支持未来的学习。
2.2.3.2
模式通知语法
如果模式信息是静态已知的,则可以进一步改进EXI语法。模式信息可以用两种不同的编码模式进行解释:严格和非严格。在严格模式下,被编码的实例必须在很大程度上对模式有效;大多数对模式的偏离都会导致编码错误。在非严格模式下,任何偏差都可以接受,并使用更通用的事件进行编码。偏差的例子是属性的实际值不匹配模式中定义的类型,或者其结构与模式中的结构不对应的元素。考虑到严格语法产生的结果更少(大多数情况下不需要SE(*)或AT(*))可以使用较短的事件代码对每个选项进行编码。与内置语法那样可以动态扩展不同,基于模式的语法是基于可用模式中的信息静态创建的。此过程将添加由模式中的属性和元素声明引导的AT(qname)或SE(qname)形式的产品。让我们继续这个例子从上一节开始,假设以下模式静态可用。
Example 2-2. Notebook (XML Schema)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="notebook">
<xs:complexType>
<xs:sequence maxOccurs="unbounded">
<xs:element name="note" type="Note"/>
</xs:sequence>
<xs:attribute ref="date" />
</xs:complexType>
</xs:element>
<xs:complexType name="Note">
<xs:sequence>
<xs:element name="subject" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
<xs:attribute ref="date" use="required" />
<xs:attribute name="category" type="xs:string"/>
</xs:complexType>
<xs:attribute name="date" type="xs:date" />
</xs:schema>
元素[note]的模式声明它有一个强制性的属性[date]和一个可选的属性[category],并且它的结构组成是元素[subject]后面跟着元素[body]。下面将显示与此元素的严格语法相对应的自动机。

Figure 2-3. Strict Schema-Informed Grammar for SE(note)
注意,AT(category)在AT(date)之前被接受,即使它们在模式中的顺序是相反的。这是因为基于模式的语法中的属性必须按字典顺序排序,首先是本地名称,然后是名称空间URI。属性排序减少了选项的数量,这反过来又大大简化了语法创建并提高了紧凑性。由于此自动机不包括AT(*)或SE(*)上的转换,任何与模式的偏差都会导致编码错误。一般来说,模式通知语法应该比内置语法更受青睐。模式知识描述了XML信息项的结构和内容类型的约束。因此,当处理和值项(如字符和属性值)根据其类型进行编码时,基于模式的语法不会动态扩展。因此,提高了处理速度和紧凑度。
2.3 内容表示
2.3.1 内置的EXI数据类型表示
EXI使用内置的数据类型表示,它以一种有效的方式表示所谓的内容值项。换句话说,所有属性和字符值都是根据与其XML Schema数据类型相关联的EXI数据类型表示进行编码的。它可以从可用的模式信息中检索类型信息。下表列出了[XML模式数据类型]和EXI中支持的内置数据类型表示之间的映射。

QName:限定名(qualified name),
是有着特定格式的xml元素,简化了名称空间的使用方法。
一份文档可能包含来自多个名称空间URI的元素和属性。因为名称空间uri可能相当长,在每个元素或者属性名中包含完整的名称空间URI是很麻烦的。
XML允许使用一种速记符号来简化为名称空间分配名称的过程。您可以创建一个简短的名称空间前缀,并将其与名称空间URI相关联。
例如,假设文档包含来自XSLT和XHTML名称空间的名称。在这种情况下,习惯上将名称空间前缀“xsl”与XSLT关联起来,使用前缀“html”来引用XHTML名称空间。
qname包含3部分:
-
名称空间前缀
-
分隔符":"
-
提供该名称空间中的元素或属性名称的本地名称
例如,这个片段说明了qname的用法:
<xsl:template match="separator">
<html:hr/>
</xsl:template>
元素模板在XSLT名称空间中,元素hr在HTML名称空间中。
您还可以使用非限定名称,它只是一个不带名称空间前缀的本地名称。这种名称的命名空间称为默认命名空间。
名称空间前缀和名称空间URI之间的关联是通过位于某个元素中的xmlns属性实现的。这个属性可以有两种形式:
-
名为 xmlns=' nsURI'的属性定义了默认命名空间的命名空间URI。此名称空间与具有非限定名称的所有元素和属性相关联。
-
一个名为 xmlns: prefix-' nsURI''的属性将给定的前缀与命名空间URI nsURI关联起来。
名为xmlns=' nsURI'的属性定义了默认命名空间的命名空间URI。此名称空间与具有非限定名称的所有元素和属性相关联。一个名为xmlns: prefix-' nsURI的属性将给定的前缀与命名空间URI nsURI关联起来。
下面是一个使用来自两个名称空间的元素的完整文档的示例:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
version="1.0">
<xsl:template match="foo">
<hr/>
</xsl:template>
</xsl:stylesheet>
在本例中,
template 元素位于XSLT名称空间中。hr元素位于默认名称空间中,它与XHTML名称空间URI相关联。
枚举值被有效地编码为n位无符号整数,其中n= [log 2 m]和m是枚举类型中的项数。序数位置(从位置0开始)按模式顺序使用枚举中的每个值项作为标识符。例外是模式联合数据类型、列表数据类型、QName或Notation以及由限制派生的类型。这些类型的值由它们各自的内置EXI数据类型表示来处理而不是被表示为枚举。
感兴趣的读者可以参考高效XML交换(EXI)格式1.0文档(
Efficient XML Interchange (EXI) Format 1.0),该文档详细描述了表示内置EXI数据类型的编码规则。当
preserve.lexicalValues 选项为true时,所有值都表示为string。一些本来会被指定为某些内置EXI数据类型表示的值被表示为具有受限字符集的string。在没有外部类型信息(没有可用的模式信息)的情况下,所有属性和字符值都被类型化为string。
2.3.2 字符串表
字符串表用于内存敏感区域,对重复出现的字符串值允许进行紧凑表示。重复出现的字符串值使用关联的紧凑标识符表示,而不是再次对字符串进行逐字编码。当在字符串表中找到字符串值(即字符串表命中)时,该值使用紧凑标识符进行编码。只有在关联表中没有找到字符串值(即字符串表缺失)时,该字符串才会被编码为string,并添加到字符串表中,分配新的紧凑标识符。
EXI将以下四个信息项放入字符串表中,并根据它们所在的上下文对字符串表进行分区。
-
uri
-
prefix
-
local-name
-
value
下表显示了2.2.2节EXI主体中使用的EXI信息项及其与字符串表分区的关系。例如,一个前缀信息项被分配给Prefix分区,而值信息项分配给value分区。

每个EXI字符串表分区都经过优化,可以更频繁地使用紧凑标识符或字符串字面值,具体取决于分区的用途。URI和Prefix分区针对频繁使用紧凑标识符(
optimized for frequent use of compact identifiers)进行了优化,而LocalName和Value分区针对频繁使用字符串字面值(
optimized for frequent use of string literals)进行了优化。
在随后的段落中,通过使用前面介绍的Notebook示例,将提供有关不同分区的更多细节。这里重复Notebook XML Document示例以简化算法说明。
<?xml version="1.0" encoding="UTF-8"?>
<notebook date="2007-09-12">
<note category="EXI" date="2007-07-23">
<subject>EXI</subject>
<body>Do not forget it!</body>
</note>
<note date="2007-09-12">
<subject>Shopping List</subject>
<body>milk, honey</body>
</note>
</notebook>
qname内容项的uri部分和uri内容项分配给URI分区。分区最初预先填充了三个可能的条目(见下图)。当提供模式时,会附加一个额外的条目,并且还会预先填充URI分区,其中包含模式中声明的每个目标名称空间的名称,以及通配符术语和属性通配符中允许的名称空间URI。

Figure 2-4.
Initial Entries in URI Partition
qname内容项的local-name部分和local-name内容项分配给LocalName分区。分别将前缀内容项分配给前缀分区。这两种分区类型最初都预先填充了可能的条目(见下图)。这些类型的分区根据关联的名称空间URI进一步区分。在我们的notebook示例中,没有使用前缀,而是使用默认的名称空间URI ("" [空字符串])。当提供模式时,LocalName分区也会预先填充模式中声明的每个属性、元素和类型的local-name,并按字典顺序排序。进一步,local-name条目按照它们在实际XML实例中出现的顺序追加(不应用额外的排序)。

Figure 2-5.
Initial Entries in Prefix and LocalName Partitions
上图以高亮显示的形式显示了整个示例文档中使用的uri和local-name项。例如,notebook示例将7个本地名称条目(如notebook和date)分配给空的URI名称空间。当再次出现local-name和/或uri信息项时,将使用紧凑标识符代替。
最后一个字符串表分区类型是Value分区。Value分区最初为空,并在处理XML实例时增长。可以限制Value项的总数或Value内容的最大字符串长度,以便在小型设备上节省内存(参见valuePartitionCapacity和valueMaxLength EXl选项)。字符串类型的属性和字符内容值分配给此分区。

Figure 2-6.
Final Entries in Value Partition
上图说明了Value内容项可以从两个不同的分区建立索引,一个是“Global”分区,一个是“Local”分区。当字符串值既不在Global值节中也不在Local值节中找到时,其字符串字面值将被编码为string,并将字符串值添加到关联的Global和Local字符串索引中。
在我们的示例中,我们假设所有值项都表示为String,就像在无模式语法中或保真度选项保留时的情况一样。lexicalValues为true。当在给定元素或属性的本地值部分中找到字符串值时,EXI可以使用相应的紧凑标识符更有效地对重新出现进行编码。在date上下文中出现两次“2007-09-12”,第二次出现导致局部值命中,并分别编码为1位压缩标识符。
另一方面,如果在本地节中找不到字符串值,但在全局节中找到,则使用相应的全局紧凑标识符。值“EXI”在笔记本示例中出现了两次,分别出现在category和subject上下文中。因此,第二次出现的结果是一个全局值hit编码为一个3位压缩标识符,因为在全局部分中有6个条目(3 = [log 2 6])。由于表大小不同,全局紧凑标识符通常不如本地紧凑标识符紧凑。尽管如此,全局值命中避免了字符串字面值的重复编码。编码压缩标识符所需的位数取决于当时关联表的实际条目数。由于所有表在解析XML实例时都在增长,因此位数不是固定的。上图说明了对整个XML实例进行编码后的情况。这种增长效应适用于所有字符串表分区,并使格式对于小文档非常紧凑。
编码压缩标识符所需的位数取决于当时关联表的实际条目数。由于所有表在解析XML实例时都在增长,因此位数不是固定的。上图说明了对整个XML实例进行编码后的情况。这种增长效应适用于所有字符串表分区,并使格式对于小文档非常紧凑。
【注意】:本节从概念层面描述EXI字符串表。表缺失和索引的精确位表示在本文档中没有给出,但在高效XML交换(EXI)格式1.0文档中(
Efficient XML Interchange (EXI) Format 1.0)有完整的描述。
2.3.3 压缩
EXI可以使用额外的计算资源来实现更高的压缩。EXI压缩利用XML知识来实现比EXI流的通用压缩更高的压缩效率。它将异构数据元素的EXI流多路复用到更同构的数据元素的通道中,这些数据元素可以更好地压缩在一起。用于组合同构数据的机制非常简单和灵活,因此它既可以用于有模式的EXI流,也可以用于无模式的EXI流。元素和属性值根据它们的qname进行分组。结构信息(如Event Codes)也被合并。为了将压缩开销保持在最小,将较小的qname通道组合起来,而单独压缩较大的通道。下图描绘了一个位包EXI体流,其中没有使用EXI压缩。灰色桶表示结构信息,彩色桶表示内容信息。颜色由相关的名称(如日期、类别、主题、正文)决定。

Figure 2-7.
EXI Body Stream
因此,可以将XML实例视为结构信息和内容信息的组合。内容信息可以根据上下文(由qname表示的周围结构)进一步划分为不同的部分。EXI以这种方式对待XML实例,并使用这些隐含的分区(称为通道)向标准压缩算法提供阻塞输入。这种对相似数据的分组提高了压缩效率。

Figure 2-8.
EXI Compression
【说明】预压缩阶段创建事件代码和内容项的字节对齐表示,与未对齐表示相比,这种表示更适合压缩算法。大多数压缩算法对一系列字节进行操作,以识别八位字节中的冗余。
通过将较小的通道合并到相同的压缩流中,而将其他通道分别压缩,EXI将压缩开销保持在最低限度。确定通道是组合还是单独压缩的机制由EXI流中存在的值内容项的数量来指导。对于小文档(
≤100个值内容项),EXI使用单个压缩流,而较大的文档(>100个值内容项)使用多个独立的压缩流。notebook
示例属于第一类,它被编码为单个压缩的deflate流,其中首先包含结构通道,然后是按文档中出现的顺序(
date, category, subject, body
)排列的qname通道。读者可以参考高效XML交换(EXI)格式1.0文档了解更多细节。
应用EXI压缩的额外任务是合理的,因为在许多用例中,编码后的文件比XML小100倍以上,比用GZip压缩后的XML紧凑14倍。此外,在大多数情况下,为实现更高的压缩而使用的计算资源少于GZip等传统压缩(参见[EXI评估说明])。
3 编码示例
4 EXI编码软件对比
工作记录:---- 对EXICodec.jar包的整体结构认识
5 EXI编解码库设计
编解码库设计框架
如何分配命令对应的编解码函数
使用cjson库
区分消息编码、片段编码、签名编码
bug及改进