6 EXIP软件分析
EXIP(EXI Processor)是一个专为嵌入式系统设计的开源C语言库,用于高效处理EXI(Efficient XML Interchange)格式数据的编码与解码,其核心目标是通过紧凑的二进制表示优化XML数据传输效率,同时降低资源消耗。
开源代码:https://sourceforge.net/projects/exip/files/exip-0.5.4.zip/download,
作者深入分析了EXIP软件的编码和解码过程,对这些软件的编码结果进行测试。实测结果表明EXIP软件输出的EXI码流并不能通用,与exicodec.jar存在兼容性问题。 以下从代码结构、功能模块及实际测试进行说明。
6.1 项目代码结构
根据开源版本exip-0.5.4的典型结构,代码库包含以下核心目录与文件:
src/:
exip_encode.c:实现EXI数据编码逻辑,将XML转换为二进制流。
exip_decode.c:解析EXI二进制流并还原为XML文档。
exi_processor.c:核心处理模块,协调编码/解码流程与内存管理。
include/:
exip.h:定义公共API接口(如exip_encode()、exip_decode())及数据结构(如EXI_Stream)。
examples/:提供基础使用示例,如XML转EXI及反向解析。
tests/:单元测试代码,验证编码/解码的正确性与性能。
6.2 核心功能模块
1 EXI流处理
-
编码流程:XML输入 → 语法事件生成(如元素开始/结束) → 二进制编码(基于模式预测与字典压缩)。
-
解码流程:EXI二进制输入 → 事件流解析 → 重构XML文档树。
-
代码示例:
EXI_Stream stream; exip_init(&stream, EXI_MODE_SCHEMA_INFORMED); // 初始化EXI处理器
exip_encode(&stream, xml_data, xml_length); // 编码XML为EXI
2 模式优化支持
-
模式感知编码:若加载XSD模式,代码通过预定义规则(如元素顺序、数据类型)跳过冗余标记,直接编码有效数据。
-
无模式编码:动态生成字典记录高频标签与属性,减少重复字符串传输。
3 内存管理
-
轻量化设计:使用静态内存分配策略(如固定大小缓冲区),避免动态内存操作对嵌入式系统的负担6。
-
代码片段:
typedef struct {
uint8_t buffer[EXIP_BUFFER_SIZE]; // 静态缓冲区
size_t offset;
} EXI_Stream;
EXIP编译后提供静态库和动态库,用户通过API函数调用进行编解码。 在examples目录下提供了完整的示例程序exipd、exipe,为用户如何调用提供了示范。
为了方便用户使用,EXIP还提供了编解码器的GUI工具:OpenEXIGUI.jar包。 这个jar包来自 exip项目代码:exip-0.5.4\externalTools,底层仍然使用exip API接口。OpenEXIGUI.jar包可以实现完整的支持xsd模式的编解码,编码路径 xml<->EXI。
作者使用OpenEXIGUI.jar工具测试了所有的ISO15118-2/20命令编码,并和EXICodec.jar编解码结果做了对比。一部分编码结果相同,一部分不同,还无法达到全部通用目的。
下面作者将详细介绍对exip、OpenEXIGUI.jar工具的研究过程和结果。
6.3 EXIP安装编译
1 在Ubuntu22.04上安装EXIP
作者在wsml和虚拟机上都安装了Ubuntu22.04,然后安装EXIP运行环境,都试验成功了。
在系统上安装gcc,g++,make工具就可以编译了。
tom@Tom-Hongtao:/mnt/c/e/codes/exip/exip-0.5.4/build/gcc$
编译静态库:
make all
编译示例程序:
make examples
编译结果输出目录: bin\examples
tom@ubuntu:/opt/exip-0.5.4/bin/examples$ ls
exipd exipd-test-schema-xsd.exi exipe-test-nested-xsd.exi
exipd-test.exi exipd-test-xsd.exi exipe-test-types-xsd.exi
exipd-test-schema.exi exipe exipe-test-xsd.exi
运行编码示例程序:
tom@ubuntu:/opt/exip-0.5.4/bin/examples$ ./exipe -help
EXIP Copyright (c) 2010 - 2012, EISLAB - Luleå University of Technology Version 0.4
Author: Rumen Kyusakov
Usage: exipe [options] [exi_out]
Options: [-help | -schema=<xsd_in>]
-schema : uses schema defined in <xsd_in> for encoding. All referenced schema files should be included in <xsd_in>
<xsd_in>: Comma-separated list of schema documents encoded in EXI with Preserve.prefixes. The first schema is the
main one and the rest are schemas that are referenced from the main one through the <xs:import> statement.
-help : Prints this help message
exi_out : output file for the EXI stream (stdout if none specified)
Purpose: This program tests the EXIP encoding functionality
tom@ubuntu:/opt/exip-0.5.4/bin/examples$
2 运行示例程序
运行环境: /mnt/hgfs/fdxc-codes/exip-0.5.4/examples/simpleEncoding
涉及的文件如下表,唯独缺少原始文件exipe-test.xml,我们后面将逐步还原出来这个文件。
源文件 | 编译后的exi文件 |
exipe-test.xml(缺少) | |
exipe-test.xsd | exipe-test.xsd.exi |
exipe-test-nested.xsd | exipe-test-nested.xsd.exi |
exipe-test-types.xsd | exipe-test-types.xsd.exi |
先运行编码示例, 生成exipe-output.exi。
tom@ubuntu:/mnt/hgfs/fdxc-codes/exip-0.5.4/bin/examples$ ./exipe -schema=exipe-test-xsd.exi,exipe-test-nested-xsd.exi,exipe-test-types-xsd.exi exipe-output.exi
Successful encoding in exipe-output.exi
tom@ubuntu:/mnt/hgfs/fdxc-codes/exip-0.5.4/bin/examples$
【说明】exipe程序是内置了待编码的xml,运行后不管有没有提供schema文件直接输出exi码流。因此exipe无法对不同的xml文件进行编码。
运行解码示例,使用上面的生成的exipe-output.exi文件, 输出了xml格式解码结果:
【说明】exipd解码过程指定了schema文件和exi码流,因此可以解码不受限制,可以是任意的exi。
tom@ubuntu:/mnt/hgfs/fdxc-codes/exip-0.5.4/bin/examples$ ./exipd -xml -schema=exipe-test-xsd.exi,exipe-test-nested-xsd.exi,exipe-test-types-xsd.exi exipe-output.exi
<?xml version="1.0" encoding="UTF-8"?>
<p0:MultipleXSDsTest
xmlns:p0="http://www.ltu.se/EISLAB/schema-test">
<p0:EXIPEncoder testByte="55" version="0.2">This is an example of serializing EXI streams using EXIP low level API</p0:EXIPEncoder>
<p0:description>This is a test of processing XML schemes with multiple XSD files</p0:description>
<p1:testSetup
xmlns:p1="http://www.ltu.se/EISLAB/nested-xsd" goal="Verify that the implementation works!">Simple test element with single attribute
</p1:testSetup>
<p0:type-test id="1001">
<p1:bool>true</p1:bool>
</p0:type-test>
<p0:extendedTypeTest>
<byteTest>11</byteTest>
<dateTimeTest>2012-07-31T13:33:55.000839</dateTimeTest>
<binaryTest>[binary: 10 bytes]</binaryTest>
<enumTest>hej</enumTest>
</p0:extendedTypeTest>
</p0:MultipleXSDsTest>
Successful parsing of the EXI stream: exipe-output.exi
tom@ubuntu:/mnt/hgfs/fdxc-codes/exip-0.5.4/bin/examples$
使用到的schema文件需要预先编码成exi格式:
-
exipe-test.xsd, 编译后exi码流是exipe-test-xsd.exi
-
exipe-test-nested.xsd, 编译后exi码流是exipe-test-nested-xsd.exi
-
exipe-test-types.xsd, 编译后exi码流是exipe-test-types-xsd.exi
【关键问题】有了exipe-test.xsd文件,怎么生成exipe-test-xsd.exi文件? 用什么工具吗?
答案是使用OpenEXIGUI.jar, 生成方法如下:
Source File: 选择exipe-test.xsd,
Destination File: 写上一个输出文件名称 exipe-test-xsd01.exi
勾选上“Include options”、 “Preserve Namespaces”
最下方的XSD File Name保持为空,
Use Schema选中 None
点击“Encode”就生成了exi文件。
【总结】 exip工具核心是根据xsd文件对xml和exi进行编解码,要求xsd文件必须预先编码成exi文件。
6.4 对notebook.xml文件编解码
本节针对notebook.xml文件使用exip工具进行编码解码,目的是检查是否能得到和参考文档一模一样的exi码流。
本节将进行无模式编码和有模式编码,使用exipd/exipe、OpenEXIGUI.jar进行交叉验证。
notebook.xml
<?xml version="1.0" encoding="UTF-8"?>
<notebook date="2007-09-12">
<note date="2007-07-23" category="EXI">
<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>
notebook.xsd
<?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>
这个xsd中定义了数据类型notebook、Note, 能够对xml中的notebook和note元素进行解释(类型、数据结构,取值范围)。 这个xml只涉及这一个xsd,是最简化的情况。后续将测试一个xml对应过个xsd文件的情况。
6.4.1 不使用xsd文件进行exi编解码测试
测试步骤
-
工具OpenEXIGUI编码生成exi, 用工具OpenEXIGUI进行解码得到xml
-
工具OpenEXIGUI编码生成exi, 用exipd进行解码得到xml
-
用exipe进行编码, 用exipd解码
-
用exipe进行编码,用工具OpenEXIGUI解码
1 工具OpenEXIGUI编码生成exi, 用工具OpenEXIGUI进行解码得到xml
源文件选择notebook.xml,点击“Encode”进行编码,生成目标文件notebook_encode.exi。
【注意】勾选“Include options”,“Preserve Namespace Declaration”。没有选中这两项会导致exipd运行失败。
接下来源文件选中notebook_encode.exi,设置目标文件为notebook_encode_decode.xml,点击“Decode”生成目标文件。
比较notebook.xml和notebook_encode_decode.xml, 观察内容一致。
2 工具OpenEXIGUI编码生成exi, 用exipd进行解码得到xml
使用上一步生成的notebook_encode.exi,用exipd解码,成功啦:
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$ ./exipd -xml notebook_encode.exi
<?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>
Successful parsing of the EXI stream: notebook_encode.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$
如果上一步转换时没有勾选“Include options”,“Preserve Namespace Declaration”,就会导致exipd运行失败。
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$ ./exipd -xml notebook_encode.exi
>Error EXIP_HEADER_OPTIONS_MISMATCH:15 at ../../src/contentIO/src/EXIParser.c, line 70
>Error EXIP_HEADER_OPTIONS_MISMATCH:15 at ../../examples/simpleDecoding/decodeTestEXI.c, line 119
Error (code: 15) during parsing of the EXI stream: notebook_encode.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$
3 用exipe进行编码, 用exipd解码
4 用exipe进行编码,用OpenEXIGUI解码
因为exipe无法对notebook.xml进行编码,因此无法验证以上两步。
【说明】作者没有研究如何使用exip API实现对notebook.xml编码,感兴趣的读者可以自行研究实现。作者认为这个C库是很有价值的,支持很多选项,能够直接解析xml文件,分解成各种语法事件,值得深入研究。
6.4.2 使用notebook.xsd文件进行exi编解码测试
测试步骤:
-
工具OpenEXIGUI编码生成exi, 用工具OpenEXIGUI进行解码得到xml
-
工具OpenEXIGUI编码生成exi, 用exipd进行解码得到xml
1 工具OpenEXIGUI编码生成exi, 用工具OpenEXIGUI进行解码得到xml
(1)编码notebook.xml,指定使用notebook.xsd文件
用OpenEXIGUI.jar,源文件选择notebook.xml,生成目标文件 notebook_encode.exi。xsd指定为notebook.xsd,“Use Schema”选中“XSD”。
点击“Encode”编码生成目标文件。
(2)用工具解码exi文件
源文件选择 notebook_encode.exi,生成目标文件notebook_encode_decode.xml。xsd指定为notebook.xsd,“Use Schema”选中“XSD”。
点击“Decode”编码生成目标文件。
比较notebook.xml和 notebook_encode_decode.xml, 二者内容一致:
2 工具OpenEXIGUI编码生成exi, 用exip进行解码得到xml
(1)用OpenEXIGUI.jar,源文件选择notebook.xsd,生成目标文件 notebook_xsd.exi。
点击“Encode”得到目标文件。
(2)再用exipd尝试解码 这个 notebook_xsd.exi, 成功!!
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$ ./exipd -xml notebook_xsd.exi
<?xml version="1.0" encoding="UTF-8"?>
<p0:schema
xmlns:p0="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<p0:element name="notebook">
<p0:complexType>
<p0:sequence maxOccurs="unbounded">
<p0:element name="note" type="Note"></p0:element>
</p0:sequence>
<p0:attribute ref="date"></p0:attribute>
</p0:complexType>
</p0:element>
<p0:complexType name="Note">
<p0:sequence>
<p0:element name="subject" type="xs:string"></p0:element>
<p0:element name="body" type="xs:string"></p0:element>
</p0:sequence>
<p0:attribute ref="date" use="required"></p0:attribute>
<p0:attribute name="category" type="xs:string"></p0:attribute>
</p0:complexType>
<p0:attribute name="date" type="xs:date"></p0:attribute>
</p0:schema>
Successful parsing of the EXI stream: notebook_xsd.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$
(3)使用上一步骤生成的 notebook_encode.exi和notebook_xsd.exi, 用exipd尝试解码,成功了!
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$ ./exipd -xml -schema=notebook_xsd.exi notebook_encode.exi
<?xml version="1.0" encoding="UTF-8"?>
<notebook date="2007-09-12T-2147483648:-2147483648:-2147483648">
<note category="EXI" date="2007-07-23T-2147483648:-2147483648:-2147483648">
<subject>EXI</subject>
<body>Do not forget it!</body>
</note>
<note date="2007-09-12T-2147483648:-2147483648:-2147483648">
<subject>shopping list</subject>
<body>milk, honey</body>
</note>
</notebook>
Successful parsing of the EXI stream: notebook_encode.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$
如果解码不指定xsd文件就会报错:
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$ ./exipd -xml notebook_encode.exi
<?xml version="1.0" encoding="UTF-8"?>
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/streamIO/src/streamRead.c, line 63
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/streamIO/src/streamDecode.c, line 79
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/streamIO/src/streamDecode.c, line 116
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/contentIO/src/bodyDecode.c, line 792
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/contentIO/src/bodyDecode.c, line 737
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/contentIO/src/bodyDecode.c, line 1298
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/contentIO/src/bodyDecode.c, line 924
>Error EXIP_UNEXPECTED_ERROR:2 at ../../src/contentIO/src/EXIParser.c, line 194
Error (code: 2) during parsing of the EXI stream: notebook_encode.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/examples$
notebook_encode.exi长度是63字节,内容如下:
00000000h: A0 09 F0 03 CB 00 15 15 61 24 07 7B 80 10 26 88 ; ???..a$.{€.&?
00000010h: DE 40 DC DE E8 40 CC DE E4 CE CA E8 40 D2 E8 42 ; 轅苻鐯剔湮疏@诣B
00000020h: 08 1E 58 03 DC DA 1B DC 1C 1A 5B 99 C8 1B 1A 5C ; ..X.苴.?.[櫲..\
00000030h: DD 00 6B 6B 4B 63 59 61 03 43 7B 73 2B C8 80 ; ?kkKcYa.C{s+葊
明显与2.3章节的编码结果不同。说明exip的编码语法规则并不是参考文档中介绍的那样,可能存在一些还不知道的默认选项,导致了结果不同。
6.5 对一个xml+多个xsd的exi编解码
上节研究了使用一个xsd作为schema编码的情况,这是最简单的应用环境。实际在ISO15118协议中存在多个复杂的xsd文件,本节研究多个xsd文件时如何进行编解码, 研究目标是exip自带的多个xsd文件。
前面exipd解码时指定的都是例子中自带的schema文件,现在需要自己编译xsd生成对应的exi文件,然后尝试exipd解码是否成功。
exipe-test_xsd.exi
exipe-test-nested-xsd.exi
exipe-test-types-xsd.exi
使用工具OpenEXIGUI, 依次对三个xsd编码生成对应的exi文件:
exipe-test.xsd --> exipe-test_xsd.001.exi
exipe-test-nested.xsd --> exipe-test-nested_xsd.001.exi
exipe-test-types.xsd --> exipe-test-types_xsd.001.exi
再次解码,成功啦!!!
tom@Tom-Hongtao:/mnt/c/e/codes/exip/simpleEncoding$ ./exipd -xml -schema=exipe-test_xsd.001.exi,exipe-test-nested_xsd.001.exi,exipe-test-types_xsd.001.exi exipe-test1_encode.exi
<?xml version="1.0" encoding="UTF-8"?>
<p0:MultipleXSDsTest xmlns:p0="http://www.ltu.se/EISLAB/schema-test">
<p0:EXIPEncoder testByte="55" version="0.2">This is an example of serializing EXI streams using EXIP low level API</p0:EXIPEncoder>
<p0:description>This is a test of processing XML schemes with multiple XSD files</p0:description>
<p1:testSetup xmlns:p1="http://www.ltu.se/EISLAB/nested-xsd" goal="Verify that the implementation works!">Simple test element with single attribute
</p1:testSetup>
<p0:extendedTypeTest>
<byteTest>11</byteTest>
<dateTimeTest>2012-07-31T13:33:55.000839</dateTimeTest>
<binaryTest>[binary: 10 bytes]</binaryTest>
<enumTest>hej</enumTest>
</p0:extendedTypeTest>
</p0:MultipleXSDsTest>
Successful parsing of the EXI stream: exipe-test1_encode.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/simpleEncoding$
【结论】 通过xsd生成exi格式文件,并且能够在解码过程中正确解码,说明了这种把xsd生成exi个方法是正确的。
6.6 对抓取的实际EXI码流和xml文件进行exip编解码测试
本节使用真实的ISO15118-2命令supportedAppProtocolReq进行编解码分析,目的是验证能否使用exipd完成解码。
6.6.1 准备数据
EVCC和SECC联网成功后,发出的第一个TCP命令就是supportedAppProtocolReq,简称SAP,目的是和SECC协商双方支持的协议和版本。 下面的json命令协议集是ISO15118-2, 版本号是2.0。
{
"supportedAppProtocolReq": {
"AppProtocol": [{
"ProtocolNamespace": "urn:iso:15118:2:2013:MsgDef",
"VersionNumberMajor": 2,
"VersionNumberMinor": 0,
"SchemaID": 1,
"Priority": 1
}]
}
}
这是标准的xml格式命令, 保存成原始文件supportedAppProtocolReq.xml。
<?xml version="1.0" encoding="UTF-8"?>
<ns0:supportedAppProtocolReq
xmlns:ns0="urn:iso:15118:2:2010:AppProtocol">
<AppProtocol>
<ProtocolNamespace>urn:iso:15118:2:2013:MsgDef</ProtocolNamespace>
<VersionNumberMajor>2</VersionNumberMajor>
<VersionNumberMinor>0</VersionNumberMinor>
<SchemaID>1</SchemaID>
<Priority>1</Priority>
</AppProtocol>
</ns0:supportedAppProtocolReq>
使用EXICodec.jar包编码后的exi流, 保存成二进制文件 supportedAppProtocolReq_src.exi。
80 00 eb ab 93 71 d3 4b 9b 79 d1 89 a9 89 89 c1 d1 91 d1 91 81 89 99 d2 6b 9b 3a 23 2b 30 02 00 00 04 00 40
SAP命令对应的xsd文件:V2G_CI_AppProtocol.xsd
<!-- This XML document originates from the ISO/IEC 15118-2 standard which can be obtained from ISO at http://www.iso.org/iso/catalogue_detail.htm?csnumber=55366 -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="urn:iso:15118:2:2010:AppProtocol"
targetNamespace="urn:iso:15118:2:2010:AppProtocol">
<xs:element name="supportedAppProtocolReq">
<xs:complexType>
<xs:sequence>
<xs:element name="AppProtocol" type="AppProtocolType" maxOccurs="20"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="supportedAppProtocolRes">
<xs:complexType>
<xs:sequence>
<xs:element name="ResponseCode" type="responseCodeType"/>
<xs:element name="SchemaID" type="idType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="AppProtocolType">
<xs:sequence>
<xs:element name="ProtocolNamespace" type="protocolNamespaceType"/>
<xs:element name="VersionNumberMajor" type="xs:unsignedInt"/>
<xs:element name="VersionNumberMinor" type="xs:unsignedInt"/>
<xs:element name="SchemaID" type="idType"/>
<xs:element name="Priority" type="priorityType"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="idType">
<xs:restriction base="xs:unsignedByte"/>
</xs:simpleType>
<xs:simpleType name="protocolNameType">
<xs:restriction base="xs:string">
<xs:maxLength value="30"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="protocolNamespaceType">
<xs:restriction base="xs:anyURI">
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="priorityType">
<xs:restriction base="xs:unsignedByte">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="20"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="responseCodeType">
<xs:restriction base="xs:string">
<xs:enumeration value="OK_SuccessfulNegotiation"/>
<xs:enumeration value="OK_SuccessfulNegotiationWithMinorDeviation"/>
<xs:enumeration value="Failed_NoNegotiation"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
6.6.2 使用工具OpenEXIGUI进行解码
运行工具软件OpenEXIGUI.jar, 源文件选择 supportedAppProtocolReq_src.exi,指定xsd文件V2G_CI_AppProtocol.xsd,配置项如图:
点击“Decode”生成解码后的文件supportedAppProtocolReq_src_decode.xml, 内容格式化后如下:
<?xml version="1.0" encoding="UTF-8"?>
<s0:supportedAppProtocolReq
xmlns:s0="urn:iso:15118:2:2010:AppProtocol"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AppProtocol>
<ProtocolNamespace>urn:iso:15118:2:2013:MsgDef</ProtocolNamespace>
<VersionNumberMajor>2</VersionNumberMajor>
<VersionNumberMinor>0</VersionNumberMinor>
<SchemaID>1</SchemaID>
<Priority>1</Priority>
</AppProtocol>
</s0:supportedAppProtocolReq>
6.6.3 使用工具OpenEXIGUI进行编码
对原始的supportedAppProtocolReq.xml文件进行编码。
运行工具软件OpenEXIGUI.jar, 源文件选择上一步生成的supportedAppProtocolReq.xml,指定xsd文件V2G_CI_AppProtocol.xsd,配置项如图:
点击“Encode”,编码生成exi文件supportedAppProtocolReq_encode.exi, 内容如下:
结果表明OpenEXIGUI生成的exi是完全相同的。
6.6.4 使用exipd进行解码
首先把V2G_CI_AppProtocol.xsd文件转换成 exi格式文件。
工具OpenEXIGUI勾选“Preserve Namespace Declaration ”、“Include options”,自己生成exi,验证exipd的解码。
再把supportedAppProtocolReq.xml携带xsd编码成exi文件supportedAppProtocolReq_encode.exi
现在验证exipd的解码:解码成功啦~~~
tom@Tom-Hongtao:/mnt/c/e/codes/exip/iso5118-2-test$ ./exipd -xml -schema=YesOptionsNoxsd-xsd.exi supportedAppProtocolReq_encode.exi
<?xml version="1.0" encoding="UTF-8"?>
<p0:supportedAppProtocolReq xmlns:p0="urn:iso:15118:2:2010:AppProtocol">
<AppProtocol>
<ProtocolNamespace>urn:iso:15118:2:2013:MsgDef</ProtocolNamespace>
<VersionNumberMajor>2</VersionNumberMajor>
<VersionNumberMinor>0</VersionNumberMinor>
<SchemaID>1</SchemaID>
<Priority>1</Priority>
</AppProtocol>
</p0:supportedAppProtocolReq>
Successful parsing of the EXI stream: supportedAppProtocolReq_encode.exi
tom@Tom-Hongtao:/mnt/c/e/codes/exip/iso5118-2-test$
【结论】 exipd的解码适应性强。
6.7 EXIP编解码流程分析
作者对exip内部的编码流程进行分析,本节记录下初步的认识,以后有机会再深入分析。
入口: \exip-0.5.4\examples\simpleEncoding\exipe.c
1 命令行参数解析
-help, printfHelp()
-schema=xxxxxx,xxxx,xxx 指定具备schema框架的exi文件。一旦指定文件,就调用parseSchema(xsdList, &schema)解析输入的文件。
最后一项参数是输出文件名, 写入outfile,并创建outfile,
2 parseSchema()
继续解析参数字符串,分隔符是等号、逗号,提取成输入文件文件名,最多支持10个xsd文件。
读取文件长度和内容,写入buffer数组。这里使用了malloc分配内存。
2.1 generateSchemaInformedGrammars()
根据输入的schema文件生成EXI语法, 结果是结构体schema:
EXIPSchema schema;
调用参数:
SchemaFormat
这里的枚举变量,使用了默认值是 SCHEMA_FORMAT_XSD_EXI, 因此输入参数文件必须是exi格式的。
如果使用SCHEMA_FORMAT_XSD_XML是否意味着可以直接使用xml文件??在头文件grammarGenerator.h中回答了:当前版本只支持 SCHEMA_FORMAT_XSD_EXI。
enum SchemaFormat
{
SCHEMA_FORMAT_XSD_EXI = 0,
SCHEMA_FORMAT_XSD_XML = 1,
SCHEMA_FORMAT_DTD = 2,
SCHEMA_FORMAT_RELAX_NG = 3
};
参数:EXIOptions* opt
参数:errorCode (*loadSchemaHandler) () 指针函数,用来指示加载内嵌的xml文件。现在不支持,默认填写为null。
没有找到实现代码,就是说不支持内嵌的xsd文件解析了。
generateSchemaInformedGrammars内部流程:
分配TreeTable内存,
初始化替代表
初始化TreeTable
初始化Schema
循环生成TreeTable
解决include/import文件引用, 解析的结果加入TreeTable
TreeTable表转成ExioSchema
释放TreeTable,释放替代表,
2.2 释放 buffer数组malloc分配的内存
3 编码, 输出字节流
tmp_err_code = encode(schemaPtr, outfile, writeFileOutputStream);
定义序列化 const EXISerializer serialize={...} EXISerializer.c