第二章 EXI协议原理与实现--7 Efficient XML编码分析(7.1~7.4)

7 Efficient XML编解码库

欧洲的 http://www.agiledelta.com公司是EXI协议发起者,也推出了一套EXI编解码库(Efficient XML)。作者联系agiledelta公司,获取了一套试用版本软件,进行了编解码测试。 测试结果表明针对ISO15118-2/20的V2G命令,大部分编解码结果是与EXICodec.jar工具一致,少部分与签名相关命令编码结果不同,不能达到互通。本节详细对Efficient XML的研究和测试过程。

7.1 EfficientXML试用版本下载、安装、激活

1价格
Efficient XML是一套收费版本,通过邮件沟通费用如下。

复制代码
1 产品许可证随数量分3档:
  10K  $44000,  $4.40/per
  100K $88000,  $0.88/per
  1M   $176000, $0.176/per
2 开发人员许可证SDK,提供一些工具(例如预处理schema的编译器)。每个SDK $1314.5。
   第一年免费支持(邮件、网络),第二年开始收费为20%($262.9/per)。
3 对每个平台收取移植费用,通常在$5,000- 10,000美元。
说实话,这个编解码库挺贵的,尤其是必须针对开发人员收取许可证SDK,对平台还要移植费用。

2下载试用版本
通过邮件沟通后拿到了下载地址和密钥,这个试用期版本有效期只有1月,现在已经过期了,公布在这里没有关系。
下载地址: http://www.agiledelta.com/efxsup_download.html
密钥:CT3JPJ-48JDW-HYF5T-32CW4-R2VVH
下载页面要注意使用最新日期的版本:
Efficient XML for C/C++, Linux Edition Version 5.3.0 516 KBytes Released 06/23/2023 这个是正确的版本

3 激活方法
在linux下解压软件包,执行许可向导:
root@Tom-Hongtao:/opt/efxc5-linux# tar -zxvf efxc530-Linux.tar.gz
root@Tom-Hongtao:/opt/efxc5-linux# cd EfxC/bin
root@Tom-Hongtao:/opt/efxc5-linux/EfxC/bin# bash ./license_wizard.sh
【注意】这个向导需要java支持,将会运行jar包,将会针对本机器生成一个激活码,以后只能在这台机器上运行软件。
弹出窗口, 黏贴邮件中的密钥即可:

点击"Next",

就用第一项,点击"Next", 注意这里出现了机器id,就是本电脑的id,意味着将要生成的许可密钥是针对本机的。

点击"Next",出现激活成功! 这里出现的LicenseKey已经是本机的密钥了。

点击"Next",出现许可密钥的使用方法:

就是需要在linxu中设置环境变量:

复制代码
root@Tom-Hongtao:/opt/efxc5-linux/EfxC/bin# export EFX_LICENSE=3SAEEN-AAMDC-UFB48-73IDD-SF7JG

如果要作为系统环境变量就要写入profile:

复制代码
root@Tom-Hongtao:/etc# vi profile

#在最后一行写入
export EFX_LICENSE=3SAEEN-AAMDC-UFB48-73IDD-SF7JG

root@Tom-Hongtao:/etc# source /etc/profile

这样以后就一劳永逸了,每次打开终端就能查看到这个环境变量:
打开一个新终端:

复制代码
tom@Tom-Hongtao:~$ export
declare -x CLASSPATH=".:/usr/lib/jvm/java-17-openjdk-amd64/lib:/usr/lib/jvm/java-17-openjdk-amd64/jre/lib"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x DISPLAY=":0"
declare -x EFX_LICENSE="3SAEEN-AAMDC-UFB48-73IDD-SF7JG"
declare -x HOME="/home/tom"

如果没有正确设置环境变量,在运行相关程序时就会出现错误提示:

复制代码
root@Tom-Hongtao:/opt/efxc5-linux/EfxC/samples# ./reader
Error detected: Unable to obtain Efficient XML license key (EFX_LICENSE) from environment. Set key in environment and try again.

7.2 编译示例程序
Efficient XML库提供了核心的编解码库,并不包含对应的C源码文件,目录内容如下:

复制代码
bin:  许可向导脚本
doc:
include: 编解码用到的函数接口
lib:  efxact.jar,核心的编解码动态链接库
samples: 示例代码,包含编解码程序
schema: 通过专用的schema工具把xsd转换成cxs文件。试用版本不提供这个工具,需要联系购买。
x32: 在PC平台上的库

查看lib下的库文件,

复制代码
tom@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/lib$ ls -l
总计 512
-rwxrwxrwx 1 tom tom  48364  8月 30 11:25 efxact.jar
-rwxrwxrwx 1 tom tom 170752  8月 30 11:25 libefx.5.3.0.a
lrwxrwxrwx 1 tom tom     15  8月 30 11:25 libefx.so -> libefx.so.5.3.0
-rwxrwxrwx 1 tom tom 154336  8月 30 11:25 libefx.so.5.3.0
-rwxrwxrwx 1 tom tom  14218  8月 30 11:25 libxml2-efx.5.3.0.a
lrwxrwxrwx 1 tom tom     20  8月 30 11:25 libxml2-efx.so -> libxml2-efx.so.5.3.0
-rwxrwxrwx 1 tom tom  18912  8月 30 11:25 libxml2-efx.so.5.3.0
-rwxrwxrwx 1 tom tom  21428  8月 30 11:25 libxmlreader.5.3.0.a
-rwxrwxrwx 1 tom tom  14712  8月 30 11:25 libxmlreader-efx.5.3.0.a
lrwxrwxrwx 1 tom tom     25  8月 30 11:25 libxmlreader-efx.so -> libxmlreader-efx.so.5.3.0
-rwxrwxrwx 1 tom tom  14784  8月 30 11:25 libxmlreader-efx.so.5.3.0
lrwxrwxrwx 1 tom tom     21  8月 30 11:25 libxmlreader.so -> libxmlreader.so.5.3.0
-rwxrwxrwx 1 tom tom  22536  8月 30 11:25 libxmlreader.so.5.3.0
-rwxrwxrwx 1 tom tom  10828  8月 30 11:25 libxmlwriter.5.3.0.a
lrwxrwxrwx 1 tom tom     21  8月 30 11:25 libxmlwriter.so -> libxmlwriter.so.5.3.0
-rwxrwxrwx 1 tom tom  14320  8月 30 11:25 libxmlwriter.so.5.3.0
tom@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/lib$

进入sample目录,包含这些示例:

复制代码
encode.c - transcode EXI to XML
decode.c - transcode XML to EXI
writer.c - uses EFXWriter APIs to write a EXI message (more efficient than transcoder in encode.c)
reader.c - uses EFXReader APIs to read a EXI message (more efficient than transcoder in decode.c)
schemaresolver.c - shows how to use a schema resolve to dynamically set a schema
io-file.c - shows how to perform I/O with files
io-buffer.c - shows how to perform I/O with buffers

flightdata.cxs - compiled schema used in the examples
flightdata.xsd - XML Schema source for the compiled schema
flightdata.xml - sample XML message
flightdata.xml.exi - EXI encoded version of the sample message

查看Makefile文件,编译所有示例程序:

复制代码
tom@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/samples$ make
gcc -o reader -O -std=c99  -w -I../include -L../lib reader.c -lefx -lz
gcc -o writer -O -std=c99  -w -I../include -L../lib writer.c -lefx -lz
gcc -o encode -O -std=c99  -w -I../include -L../lib encode.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
gcc -o decode -O -std=c99  -w -I../include -L../lib decode.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
gcc -o io-buffer -O -std=c99  -w -I../include -L../lib io-buffer.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
gcc -o io-file -O -std=c99  -w -I../include -L../lib io-file.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
gcc -o set-string-table -O -std=c99  -w -I../include -L../lib set-string-table.c -lefx -lz
gcc -o string-intern -O -std=c99  -w -I../include -L../lib  string-intern.c -lefx -lz
gcc -o dtrm-guid -O -std=c99  -w -I../include -L../lib dtrm-guid.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
gcc -o dtrm-list -O -std=c99  -w -I../include -L../lib dtrm-list.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
gcc -o schemaresolver -O -std=c99  -w -I../include -L../lib schemaresolver.c -lefx -lz
gcc -o settings-file-use -O -std=c99  -w -I../include -L../lib settings-file-use.c -lefx -lz -lxmlreader-efx -lxmlwriter -lxmlreader
tom@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/samples$

随便挑一个程序来运行,会出现这样的错误提示:

复制代码
error while loading shared libraries: libefx.so:cannot open shared object file: No such file or directory

这时因为还没有在系统中声明这些lib库的路径,程序傻傻的找不到。

7.3 设置动态链接库路径

现在我们需要用root用户进行操作,为系统设置正确的动态链接库路径。
一般用户自己的库都存放到 /usr/local/lib下面, 我们把efficientXML的这些lib拷贝到这个目录

复制代码
root@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/lib# cp -a lib*.* /usr/local/lib/efficientXML/
root@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/lib#

要把这个路径添加到动态链接库搜索路径中。
linux系统默认的库搜索路径是/lib和/usr/lib目录,要增加一个搜索路径需要修改动态链接库配置文件:

复制代码
root@Tom-Hongtao:/usr/local/lib# vi /etc/ld.so.conf

include /etc/ld.so.conf.d/*.conf
/usr/local/lib/efficientXML      #添加这一个路径

#更新配置
root@Tom-Hongtao:/usr/local/lib# ldconfig
/sbin/ldconfig.real: /usr/lib/wsl/lib/libcuda.so.1 不是符号链接

root@Tom-Hongtao:/usr/local/lib#

现在就大功告成了,随意运行程序都能找到efficientXML的这些动态库了。
查看应用程序使用的动态库

复制代码
root@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/samples# ldd reader
        linux-vdso.so.1 (0x00007ffda4de9000)
        libefx.so => /usr/local/lib/efficientXML/libefx.so (0x00007ff37c600000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007ff37c903000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff37c3d8000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff37c930000)
root@Tom-Hongtao:/mnt/c/E/codes/EfficientXML/EfxC/samples#

从上面就能看出来libefx.so指向了我们刚刚配置的动态库路径,OK!!!

7.4 分析samples程序

本节分析编解码程序,说明关键的库函数调用方法。

7.4.1 示例使用的xml文件

flightdata.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<p0:dailyFlightInfo xmlns:p0="http://www.example.com/flightdata">
    <day>2003-10-10</day>
    <flightInfo>
        <airline>Alaska</airline>
        <departure>
            <airport>LAX</airport>
            <time>
                <hour>7</hour>
                <minute>35</minute>
            </time>
        </departure>
        <arrival>
            <airport>SEA</airport>
            <time>
                <hour>9</hour>
                <minute>15</minute>
                <status>ON-TIME</status>
            </time>
        </arrival>
    </flightInfo>
    <flightInfo>
        <airline>United</airline>
        <departure>
            <airport>SFO</airport>
            <time>
                <hour>19</hour>
                <minute>40</minute>
            </time>
        </departure>
        <arrival>
            <airport>BSO</airport>
            <time>
                <hour>22</hour>
                <minute>25</minute>
                <status>CANCELLED</status>
            </time>
        </arrival>
    </flightInfo>
</p0:dailyFlightInfo>

flightdata.xsd:

复制代码
<?xml version="1.0" ?>
<xs:schema targetNamespace="http://www.example.com/flightdata"
           xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:ns="http://www.example.com/flightdata" >
  <xs:element name="dailyFlightInfo">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="day" type="xs:date" />
        <xs:element name="flightInfo" type="ns:FlightInfoType" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:complexType name="FlightInfoType">
    <xs:sequence>
      <xs:element name="airline" type="xs:NCName" />
      <xs:element name="departure" type="ns:FlightType" />
      <xs:element name="arrival" type="ns:FlightType" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="FlightType">
    <xs:sequence>
      <xs:element name="airport" type="ns:AirportType" />
      <xs:element name="time" type="ns:TimeType" />
    </xs:sequence>
  </xs:complexType>

  <xs:simpleType name="AirportType">
    <xs:restriction base="xs:NCName">
      <xs:pattern value="[A-Z]{3}" />
    </xs:restriction>
  </xs:simpleType>

  <xs:complexType name="TimeType">
    <xs:sequence>
      <xs:element name="hour" type="ns:HourType" />
      <xs:element name="minute" type="ns:MinuteType" />
      <xs:element name="status" type="ns:StatusType" minOccurs="0" />
    </xs:sequence>
  </xs:complexType>

  <xs:simpleType name="StatusType">
    <xs:restriction base="xs:NCName">
      <xs:enumeration value="ON-TIME" />
      <xs:enumeration value="DELAYED" />
      <xs:enumeration value="CANCELLED" />
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="HourType">
    <xs:restriction base="xs:int">
      <xs:minInclusive value="0"/>
      <xs:maxInclusive value="23"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="MinuteType">
    <xs:restriction base="xs:int">
      <xs:minInclusive value="0"/>
      <xs:maxInclusive value="59"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>

flightdata.cxs --- 这是用schema compile对flightdata.xsd编译后的exi文件。试用版本库没有提供该编译器。

7.4.2 编码文件encode.c

编码是把xml文件变成exi文件,带有xsd的编码核心流程:

复制代码
EFXXMLParseError pError;
EFXFactory * pFactory;
EFXFactoryAlloc(&pFactory);

FILE *in, *out;
in = fopen(fileName, "r");           //fileName = "flightdata.xml"; 指定源文件
out = fopen(encodedFileName, "wb");  //encodedFileName = "flightdata-xcode.xml.exi" 这时输出的exi文件名

EFXFactorySetSchema(pFactory, 0, 0, cxsFileName);   //cxsFileName = "flightdata.cxs"; 指定schema文件
EFXTranscoderEncode(pFactory, FileFill, in, fileName, FileFlush, out, &pError));  //编码

fclose(in);
fclose(out);
EFXFactoryFree(pFactory);  //释放内存

7.4.3 解码文件decode.c

解码是把exi变成xml文件,核心流程如下:

复制代码
EFXXMLParseError pError;
EFXFactory * pFactory;
EFXFactoryAlloc(&pFactory);

FILE *in, *out;
in = fopen(encodedFileName, "rb");   //encodedFileName = "flightdata.xml.exi"
out = fopen(decodedFileName, "w");   //decodedFileName = "flightdata-xcode-out.xml"  输出的xml文件名

EFXFactorySetSchema(pFactory, 0, 0, cxsFileName);   //cxsFileName = "flightdata.cxs"; 指定schema文件
EFXTranscoderDecode(pFactory, FileFill, in, FileFlush, out);  //解码

fclose(in);
fclose(out);
EFXFactoryFree(pFactory);  //释放内存

7.4.4 设置option选项文件 settings-file-use.c

该文件做了两部分操作:使用设置文件进行编码,然后手动设置option选项进行解码。
(1)读取设置文件flightdata-settings.xml,包含两个option:

复制代码
<!-- definitions of the settings can be found in the Java doc for EFXProperty -->
<settings xmlns="http://agiledelta.com/efx/settings/">
  <compression>false</compression>
  <stringvalues>true</stringvalues>
</settings>
​

这两个选项将会对编码过程起作用,导致编码出来的Header和Body有所不同。
核心流程:

复制代码
//加载设置文件,自动配置option
EFXFactoryLoadSettingsFromPath(pFactory, settingsFileName, &pError)  //settingsFileName = "flightdata-settings.xml"

(2)手动设置option选项

复制代码
//手动设置option选项,不使用设置文件
EFXFactorySetProperty(pFactory, EFXPROPERTY_COMPRESSION, 0);  // turning off compression makes output bit-aligned

到此为止,作者介绍完了Efficient XML库的基本编解码用法,接下来就要进行各种测试了。

预告:
7.5 Efficient XML库和OpenEXI.jar编解码交叉测试
7.6 EFXReader用法示例
7.7 测试ISO15118-2命令SessionSetupReq、SessionSetupRes
7.8 测试ISO15118-20命令supportedAppProtocolReq、supportedAppProtocolRes

相关推荐
快活林高老大2 天前
第二章 EXI协议原理与实现--5 EXICodec.jar软件分析
iso15118·exi
快活林高老大3 天前
第二章 EXI协议原理与实现--7.5 Efficient XML库和OpenEXI.jar编解码交叉测试
iso15118·exi