转载自http://www.cnblogs.com/me-sa/archive/2012/07/20/erlang_xml.html

XML以及相关的XSLT,XPath,XSD工具在数据层面为我们提供了极大的灵活性和便利.我们游戏协议的代码自动生成就是首先使用XSD工具设计了协议的Schema,然后使用.net的xsd工具直接生成实体类,然后就直接在工具中操作对象就可以了,协议的XML文件也可以通过事先的Schema检查来校验数据规范性;Erlang类库提供了对于XML的支持,可能你在STDLIB中并没有找到,这是因为这部分被独立在:http://www.erlang.org/doc/apps/xmerl/index.html

如果已经忘记了XML中常用的概念,最好还是在维基百科中做一下回顾:

  • XML XHTML   DTD(文件类型描述) XML Schema   XLink    SVG  XSLT   X3D SAX
  • W3C的XML课程  http://www.w3school.com.cn/x.asp

我们可以在"\erl5.9.1\lib\xmerl-1.3.1\include\xmerl.hrl"头文件中看到XML的上述各种概念在Erlang中的表达形式;

%% XML Element
%% content = [#xmlElement()|#xmlText()|#xmlPI()|#xmlComment()|#xmlDecl()]
-record(xmlElement,{name,               % atom()expanded_name = [],     % string() | {URI,Local} | {"xmlns",Local}nsinfo = [],             % {Prefix, Local} | []namespace=#xmlNamespace{},parents = [],          % [{atom(),integer()}]pos,               % integer()attributes = [],     % [#xmlAttribute()]content = [],language = "",     % string()xmlbase="",           % string() XML Base path, for relative URI:selementdef=undeclared % atom(), one of [undeclared | prolog | external | element]}).

Erlang官方解决方案从模块划分上看是五脏俱全的:xmerl_scan,xmerl,xmerl_xs,xmerl_eventp,xmerl_xpath,xmerl_xsd,xmerl_sax_parser;但是官方文档上并没有给出足够低门槛的demo代码,仅有的两段示例代码可能由于搜索引擎收录的问题,并不容易找到,其实他们是在:

http://erlang.org/doc/apps/xmerl/xmerl_xs_examples.html

http://www.erlang.org/doc/apps/xmerl/xmerl_xs_examples.html

如果你已经安装了Erlang那么你可以在下面的路径找到它们:erl5.9.1\lib\xmerl-1.3.1\doc\html;我们还是通过两段最简单的代码看看如何使用吧.
 

解析&创建XML

解析XML
首先我们为这次demo设计一个简单的xml文件test.xml,比如:

<shopping> <item name="bread" quantity="3" price="2.50"/> <item name="milk" quantity="2" price="3.50"/>
</shopping>

我们要解析上面的xml文件计算得到购物清单的总金额,使用xmerl可以这样做:
-include_lib("xmerl/include/xmerl.hrl").
-export([get_total/1]).get_total(ShoppingList) ->{XmlElt, _} = xmerl_scan:string(ShoppingList),Items = xmerl_xpath:string("/shopping/item", XmlElt),Total = lists:foldl(fun(Item, Tot) ->[#xmlAttribute{value = PriceString}] = xmerl_xpath:string("/item/@price", Item),{Price, _} = string:to_float(PriceString),[#xmlAttribute{value = QuantityString}] = xmerl_xpath:string("/item/@quantity", Item),{Quantity, _} = string:to_integer(QuantityString),Tot + Price*Quantityend,0, Items),io:format("$~.2f~n", [Total]).

运行上面的代码得到结果:$14.50

动态创建XML 

下面我们从CSV文件数据源动态创建一个XML,CSV内容如下:

bread,3,2.50 
milk,2,3.50

要创建的XML如下,其实就是上面的购物清单:

<shopping> <item name="bread" quantity="3" price="2.50"/> <item name="milk" quantity="2" price="3.50"/> </shopping>

实现代码:

to_xml(ShoppingList) ->Items = lists:map(fun(L) ->[Name, Quantity, Price] = string:tokens(L, ","),{item, [{name, Name}, {quantity, Quantity}, {price, Price}], []}end, string:tokens(ShoppingList, "\n")),xmerl:export_simple([{shopping, [], Items}], xmerl_xml).

官方给出的解决方案确实差强人意,甚至有人被惹恼,比如 [erlang-questions] Rant: I hate parsing XML with Erlang 其实我们还有别的选择,比如erlsom

erlsom

erlsom 项目地址:http://sourceforge.net/projects/erlsom/ erlsom支持三种使用模型:

  1. as a SAX parser. 备注: SAX即Simple API for XML(简称SAX)是个循序存取XML的解析器API.
  2. As a simple sort of DOM parser. 备注: DOM(Document Object Model)是W3C组织推荐的处理可扩展置标语言的标准编程接口.
  3. As a ‘data binder’ 直接解析成为Erlang的Record,类似于一个强类型DataSet的概念

下面我们实际操练一下这三种模式,我们使用下面的xml,文件名test2.xml,目标还是计算购物清单的中金额

<?xml version="1.0"?>
<shopping> <item name="bread" quantity="3" price="2.50"/> <item name="milk" quantity="2" price="3.50"/>
</shopping>

 
SAX parser
2>  {ok, Xml} = file:read_file("test.xml").
{ok,<<"<shopping> \r\n  <item name=\"bread\" quantity=\"3\" price=\"2.50\"/> \r\
n  <item name=\"milk\" quantity=\"2\" price=\"3.50"...>>}
3> erlsom:parse_sax(Xml, [], fun(Event, Acc) -> io:format("~p~n", [Event]), Acc end).
startDocument
{startElement,[],"shopping",[],[]}
{ignorableWhitespace," \r\n  "}
{startElement,[],"item",[],[{attribute,"price",[],[],"2.50"},{attribute,"quantity",[],[],"3"},{attribute,"name",[],[],"bread"}]}
{endElement,[],"item",[]}
{ignorableWhitespace," \r\n  "}
{startElement,[],"item",[],[{attribute,"price",[],[],"3.50"},{attribute,"quantity",[],[],"2"},{attribute,"name",[],[],"milk"}]}
{endElement,[],"item",[]}
{ignorableWhitespace," \r\n"}
{endElement,[],"shopping",[]}
endDocument
{ok,[]," "}
4> Sum = fun(Event, Acc) -> case Event of {startElement, _, "item", _, [{_,_,_,_,P},{_,_,_,_,C},_]} -> Acc + list_to_float(P)*list_to_integer(C); _ -> Acc end end.
#Fun<erl_eval.12.82930912>
5> erlsom:parse_sax(Xml, 0, Sum).
{ok,14.5," "}
6>

DOM parser
使用下面的代码解析出来的结果由于精简掉了XML的架构信息,所以清爽简单了很多,后续计算略;

9> erlsom:simple_form(Xml).
{ok,{"shopping",[],[{"item",[{"price","2.50"},{"quantity","3"},{"name","bread"}],[]},{"item",[{"price","3.50"},{"quantity","2"},{"name","milk"}],[]}]}," "}
10>

Data Binder

首先设计XML的XSD,然后使用XSD打通数据模型使用的各个环节,比如生成C#代码,直接获得强类型的对象,这个方法在.net里面很常用;erlsom提供的Data binder的模式,其实就是实现了这种设计方法;起点还是设计XSD文件,好吧,我们为上面的test2.xml设计一个XSD,如下:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:element name="shopping" type="shoppingType"/>
<xsd:complexType  name="shoppingType"><xsd:sequence><xsd:element name="item" minOccurs="0" maxOccurs="unbounded"><xsd:complexType><xsd:attribute name="name" type="xsd:string" use="required"/><xsd:attribute name="quantity" type="xsd:positiveInteger" use="required"/><xsd:attribute name="price" type="xsd:decimal" use="required"/></xsd:complexType></xsd:element></xsd:sequence></xsd:complexType >
</xsd:schema>

然后我们通过XSD生成对应的record,这个erlsom已经提供了工具:
 28> erlsom:write_xsd_hrl_file("test.xsd","test.hrl").
ok

打开test.hrl,对应的record已经生成:
%% HRL file generated by ERLSOM
%%
%% It is possible to change the name of the record fields.
%%
%% It is possible to add default values, but be aware that these will
%% only be used when *writing* an xml document.-record('shoppingType', {anyAttribs, 'item'}).
-record('shoppingType/item', {anyAttribs, 'name', 'quantity', 'price'}).

为了能在Erlang Shell中完成所有的测试,后面需要使用record的时候我们使用rd()命令,在shell中建立record的定义.

下面就是解析并映射为record了:

Eshell V5.9.1  (abort with ^G)
1>  {ok, X} = erlsom:compile_xsd_file("test.xsd").=ERROR REPORT==== 20-Jul-2012::06:53:09 ===
Call to tuple fun {erlsom_parse,xml2StructCallback}.Tuple funs are deprecated and will be removed in R16. Use "fun M:F/A" instead, f
or example "fun erlsom_parse:xml2StructCallback/2".(This warning will only be shown the first time a tuple fun is called.){ok,{model,[{type,'_document',sequence,[{el,[{alt,shopping,shoppingType,[],1,1,true,undefined}],1,1,1}],[],undefined,undefined,1,1,1,false,undefined},{type,shoppingType,sequence,[{el,[{alt,item,'shoppingType/item',[],1,1,true,undefined}],0,unbound,1}],[],undefined,undefined,2,1,1,undefined,undefined},{type,'shoppingType/item',sequence,[],[{att,name,1,false,char},{att,quantity,2,false,char},{att,price,3,false,char}],undefined,undefined,4,1,1,undefined,undefined}],[{ns,"http://www.w3.org/2001/XMLSchema","xsd"}],undefined,[]}}
2> {ok, Xml} = file:read_file("test2.xml").
{ok,<<"锘??xml version=\"1.0\"?>\r\n<shopping> \r\n  <item name=\"bread\" quanti
ty=\"3\" price=\"2.50\"/> \r\n  <item name=\"milk"...>>}
3> {ok, Result, _} = erlsom:scan(Xml, X).
{ok,{shoppingType,[],[{'shoppingType/item',[],"bread","3","2.50"},{'shoppingType/item',[],"milk","2","3.50"}]}," "}
4>

对于不太复杂的XML,解析到这种程度实际上已经非常方便处理了,完全可以在此停住完成最终运算;但是对于特别复杂的XML使用Record处理,更灵活直观,我们把这个流程走完:

5> rd('shoppingType', {anyAttribs, 'item'}).
shoppingType
6> rd('shoppingType/item', {anyAttribs, 'name', 'quantity', 'price'}).
'shoppingType/item'
7> R4#shoppingType.'item'.
[#'shoppingType/item'{anyAttribs = [],name = "bread",quantity = "3",price = "2.50"},
#'shoppingType/item'{anyAttribs = [],name = "milk",quantity = "2",price = "3.50"}]8> hd(R4#shoppingType.'item').
#'shoppingType/item'{anyAttribs = [],name = "bread",quantity = "3",price = "2.50"}
9> #'shoppingType/item'.quantity.
4

其它可选方案

[1] JSON 作为轻量级的数据交换格式,JSON有着巨大的优势,erlang相关解决方案也有很多比如ejson mochiweb也有相关模块

[2] Google的Protocol Buffers 以及Facebook的Thrift为代表的解决方法

[3] Piqi includes a data serialization system for Erlang. It can be used for serializing Erlang values in 4 different formats: Google Protocol Buffers, JSON, XML and Piq. http://piqi.org/#usecasesandlimitations

[4]ASN.1      ASN.1本身只定义了表示信息的抽象句法,但是没有限定其编码的方法。各种ASN.1编码规则提供了由ASN.1描述其抽象句法的数据的值的传送语法(具体表达)。标准的ASN.1编码规则有基本编码规则(BER,Basic Encoding Rules)、规范编码规则(CER,Canonical Encoding Rules)、唯一编码规则(DER,Distinguished Encoding Rules)、压缩编码规则(PER,Packed Encoding Rules)和XML编码规则(XER,XML Encoding Rules)。为了使ASN.1能够描述一些原先没有使用ASN.1定义,因此不适用上述任一编码规则的数据传输和表示的应用和协议,另外制订了ECN来扩展ASN.1的编码形式。ECN可以提供非常灵活的表明方法,但还没有得到普遍应用。

ASN.1与特定的ASN.1编码规则一起通过使用独立于计算机架构和编程语言的方法来描述数据结构,为结构化数据的交互提供了手段,特别是在网络环境的应用程序。

Erlang对ASN.1支持:

The Asn1 application provides:
• An ASN.1 compiler for Erlang, which generates encode and decode functions to be used by Erlang programs
sending and receiving ASN.1 specified data.
• Run-time functions used by the generated code.
• The supported encoding rules are:
• Basic Encoding Rules (BER)
• Distinguished Encoding Rules (DER), a specialized form of BER that is used in security-conscious
applications.
• Packed Encoding Rules (PER) both the aligned and unaligned variant.

相关:

[墙内] Processing XML in Erlang http://www.cnblogs.com/me-sa/articles/2673940.html
record to xml http://www.cnblogs.com/me-sa/articles/2673945.html

http://userprimary.net/posts/2011/02/16/Generating-XML-in-Erlang-Using-xmerl/

http://www.erlang.org/doc/apps/xmerl/xmerl_xs_examples.html
http://www.sics.se/~joe/ericsson/xml/xml.html
http://sourceforge.net/scm/?type=cvs&group_id=157642
http://stackoverflow.com/questions/3517914/erlang-xml-to-tuples-and-lists

[Erlang] XML处理方案相关推荐

  1. erlang xml 解析_用yecc(erlang)写一个json解析器

    昨天写了个json的解析器.其实yecc早看过了,只是那时对自己要求太高,想一下子写个小语言.然后大脑就陷入混乱... 后来注意力转移了.就不那么急着去开发些难道大的.今天回来一看,觉得都理解了,实践 ...

  2. Docker Centos 7.X部署Tomcat 并且修改Server.xml配置文件方案 并设置时区 只要十一步

    我用的是腾讯云 Centos 7.3版本,使用Docker最好使用7.x以上版本 1.拉取镜像 docker pull tomcat:8 2.创建容器并且挂载webapps的目录(我这里将本地端口映射 ...

  3. python 中使用ElementTree操作XML

    概述 对比其他 Python 处理 XML 的方案,xml.etree.ElementTree 模块(下文我们以 ET 来表示)相对来说比较简单,接口也较友好. 官方文档 里面对 ET 模块进行了较为 ...

  4. Android 创建与解析XML(一)—— 概述

    Android 是最常用的智能手机平台,XML 是数据交换的标准媒介,Android 中可以使用标准的XML生成器.解析器.转换器 API,对 XML 进行解析和转换. XML,相关有DOM.SAX. ...

  5. pythonxml模块高级用法_Python利用ElementTree模块处理XML的方法详解

    前言 最近因为工作的需要,在使用 Python 来发送 SOAP 请求以测试 Web Service 的性能,由于 SOAP 是基于 XML 的,故免不了需要使用 python 来处理 XML 数据. ...

  6. Sql Server参数化查询之where in和like实现之xml和DataTable传参

    在上一篇Sql Server参数化查询之where in和like实现详解中介绍了在Sql Server使用参数化查询where in的几种实现方案,遗漏了xml和表值参数,这里做一个补充 文章导读 ...

  7. QT文本编辑器配色方案 深色主题

    QT 文本编辑器配色方案(深色主题) 上效果图,先睹为快: 配置方案下载: 链接:https://pan.baidu.com/s/1KOYxz75pawz8duDTFYd91Q 提取码:ukds 将下 ...

  8. 【erlang】吃螃蟹 rust 开发 erlang nif 的正确方式 rustler

    用rust编写erlang的nif方案,以下几个star比较高 Rustler ( https://github.com/hansihe/rustler ) 这个比较火,但是没有关于如何在 Erlan ...

  9. 第九章 深入拨号方案

    现在,我们已经对FreeSwitch的XML配置及其强大的XML拨号方案的工作原理有了更多的基本了解. 现在是时候超越那种"我知道怎么做,但不完全理解为什么他们会那样做"的感觉了. ...

最新文章

  1. VS生成dll和lib库文件
  2. python中lambda 表达式(无参数、一个参数、默认参数、可变参数(*args、**kwargs)、带判断的lambda、列表使用lambda)
  3. python:ElementTree操作XML
  4. python数据挖掘试题四十道,你敢来挑战吗?
  5. html外边框设为虚线,科技常识:html设置虚线边框的方法
  6. python tkinter库四则运算_python tkinter 编写心理学试验程序干扰任务之四则运算 psychopy...
  7. ActiveMQ 权限
  8. python中文叫什么-python中文别名
  9. 多智能体协同视觉SLAM技术研究进展
  10. 这篇文章写给想学计算机视觉还没开始的人
  11. JavaScript使用正则表达式做表单验证
  12. 药事管理学名词解释和问答题题集
  13. VS2017社区版离线下载
  14. Zipf law 定律
  15. mysql获取字符串长度函数(CHAR_LENGTH)
  16. c语言小兔子原来有1个萝卜,体能《小兔子运萝卜》.doc
  17. 剑指Offer之二维数组中的查找
  18. 完全免费:鲜为人知的桌面正文内容检索工具(支持epub/mobi/azw3/markdown)
  19. jquery按钮加载动画插件loda-button
  20. idea关闭当前窗口的快捷键

热门文章

  1. Trends in Plant Science | 植物微生物群失调与安娜-卡列尼娜原则
  2. 立创商城pcb封装导入
  3. JavaScript进阶篇③ — 浏览器对象、Dom对象
  4. 为什么刹车热了会失灵_急!我的刹车为什么突然不管用了?
  5. c语言搜题答案软件软件,大学c语音搜题
  6. cura同时打印多个东西,cura同时打开多个模型,cura打开多个stl
  7. 【转】蜗牛求职记之华为篇
  8. 三相PFC程序30KW充电桩 采用目前最常用的TI DSP数字信号处理芯片
  9. xd导出标注html,Adobe XD免费交付神器 标记狮MarkLion 一键导出离线标注网页
  10. ZJUT online OJ c++通关模拟题(problem1335-problem1516) 题解