本文档主要讲述Erlang中的XML相关的。
Erlang XML
xmerl_scan
This module is the interface to the XML parser, it handles XML 1.0.
这个模块是XML解析器的接口,它处理XML 1.0。
XML解析器是通过xmerl_scan:string/[1,2]或xmerl_scan:file/[1,2]来激活的。它返回xmerl.hrl中定义的类型的记录。参见定制函数教程。
数据类型
1.document() = xmlElement() | xmlDocument()
由xmerl_scan:string/[1,2]和xmerl_scan:file/[1,2]返回的文档。返回记录的类型取决于传递给函数的文档选项的值。
2.global_state()
扫描器的全局状态,由#xmerl_scanner{}记录表示。
3.option_list()
选项允许自定义扫描程序的行为。参见定制函数教程。
可能的选项是:
- {acc_fun, Fun}
调用函数来积累实体内容。 - {continuation_fun, Fun} | {continuation_fun, Fun, ContinuationState}
回调函数,以决定如果扫描仪在文档完成之前运行到EOF时该做什么。 - {event_fun, Fun} | {event_fun, Fun, EventState}
回调函数来处理扫描事件。 - {fetch_fun, Fun} | {fetch_fun, Fun, FetchState}
调用函数获取外部资源。 - {hook_fun, Fun} | {hook_fun, Fun, HookState}
调用回调函数来处理标识后的文档实体。 - {close_fun, Fun}
当文档被完全解析时调用。 - {rules, ReadFun, WriteFun, RulesState} | {rules, Rules}
处理解析时扫描程序信息的存储。 - {user_state, UserState}
可从所有自定义函数访问的全局状态变量 - {fetch_path, PathList}
路径列表是获取文件时要搜索的目录列表。如果有问题的文件不在fetch_path中,则URI将用作文件名。 - {space, Flag}
‘preserve’(默认值)用于保留空格,’normalize’用于累积连续的空格并将其替换为一个空格。 - {line, Line}
指定扫描包含XML片段的文档的起始行。 - {namespace_conformant, Flag}
控制是否作为与名称空间一致的XML解析器,“false”(默认)为“true”。 - {validation, Flag}
控制是否作为验证XML解析器处理:’off’(默认)不进行验证,或通过dtd验证’dtd’或通过XML schema验证’schema’。如果使用“false”等于“off”和“true”等于“dtd”,则“false”和“true”选项是过时的(即它们可能在将来的版本中被删除)。 - {schemaLocation, [{Namespace,Link}|…]}
显式地告诉要使用哪个XML模式文档来验证XML文档。与{validation,schema}选项一起使用。 - {quiet, Flag}
如果xmerl应该安静地运行,不向标准输出输出任何信息,则将其设置为“true”(默认为“false”)。 - {doctype_DTD, DTD}
允许指定在XML文档中不可用的DTD名称。此选项仅与{validation,’dtd’选项一起有效。 - {xmlbase, Dir}
XML基础目录。如果使用string/1,默认是当前目录。如果使用file/1,默认是给定文件的目录。 - {encoding, Enc}
设置使用的默认字符集(默认UTF-8)。只有在XML声明没有显式给出时才使用这个字符集。 - {document, Flag}
如果xmerl应该以xmlDocument记录的形式返回完整的XML文档,则将其设置为’true’(默认为’false’)。 - {comments, Flag}
如果xmerl应该跳过注释,则将其设置为“false”,否则将返回xmlComment记录(默认为“true”)。 - {default_attrs, Flag}
如果xmerl应该为元素添加定义了默认值的缺失属性(默认值为“false”),则将其设置为“true”。
4.xmlDocument() = #xmlDocument{}
5.xmlElement() = #xmlElement{}
导出函数
1.accumulate_whitespace(T::string(), S::global_state(), X3::atom(), Acc::string()) -> {Acc, T1, S1}
函数用于累积和规格化空白。
2.cont_state(S::global_state()) -> global_state()
Equivalent to cont_state(ContinuationState, S).
3.cont_state(X::ContinuationState, S::global_state()) -> global_state()
用于控制ContinuationState,将在延续函数中使用,并在解析器遇到字节流结束时调用。参见自定义函数教程。
4.event_state(S::global_state()) -> global_state()
Equivalent to event_state(EventState, S).
5.event_state(X::EventState, S::global_state()) -> global_state()
6.fetch_state(S::global_state()) -> global_state()
7.fetch_state(X::FetchState, S::global_state()) -> global_state()
8.file(Filename::string()) -> {xmlElement(), Rest}
9.file(Filename::string(), Options::option_list()) -> {document(), Rest}
10.hook_state(S::global_state()) -> global_state()
11.hook_state(X::HookState, S::global_state()) -> global_state()
12.rules_state(S::global_state()) -> global_state()
13.rules_state(X::RulesState, S::global_state()) -> global_state()
14.string(Text::list()) -> {xmlElement(), Rest}
15.string(Text::list(), Options::option_list()) -> {document(), Rest}
16.user_state(S::global_state()) -> global_state()
17.user_state(X::UserState, S::global_state()) -> global_state()
XMERL (xmerl)
用于将XML数据导出为外部格式的函数。
导出函数
1.callbacks(Module) -> Result
Types
Module = atom()
Result = [atom()]
查找给定模块的继承回调模块列表。
2.export(Content, Callback) -> ExportedFormat
Equivalent to export(Data, Callback, []).
3.export(Content, Callback, RootAttributes) -> ExportedFormat
Types
Content = [Element]
Callback = atom()
RootAttributes = [XmlAttributes]
使用指定的回调模块导出正常的、格式良好的XML内容。
Element is any of:
- #xmlText{}
- #xmlElement{}
- #xmlPI{}
- #xmlComment{}
- #xmlDecl{}
(见xmerl.hrl记录定义)。#xmlText{}元素中的文本可以是字符和/或二进制文件的深层列表
RootAttributes是#root#元素的#xmlAttribute{}属性列表,它隐式地成为给定内容的父元素。因此,使用完整导出的内容数据调用#root#的标记处理函数。根属性可用于指定,如编码或XML或HTML文档的其他元数据。
回调模块应该包含数据结构中所有标记的钩子函数。一个钩子函数必须有以下格式:其中E是对应的#xmlElement{}, Data是E已经导出的内容,Attributes是E的#xmlAttribute{}记录列表。最后,parent是E的父节点列表,形式为[{ParentTag::atom(), ParentPosition::integer()}]。1
Tag(Data, Attributes, Parents, E)
钩子函数应该返回要导出的数据,或者返回一个元组{‘#xml-alias#’, NewTag::atom()},或者返回一个元组{‘#xml-redefine#’,Content},其中内容是一个内容列表(可以是简单形式的;详见export_simple/2)。
回调模块可以通过所需的函数’#xml- inter# () -> [ModuleName::atom()]从其他回调模块继承定义。
See also: export/2, export_simple/3.
4.export_content(Es::Content, Callbacks) -> term()
Types
Content = [Element]
Callback = [atom()]
直接导出普通的XML内容,不需要进一步的上下文。
5.export_element(E, CB) -> term()
直接导出普通的XML元素,不需要进一步的上下文。
6.export_element(E, CallbackModule, CallbackState) -> ExportedFormat
用于在XML文档的解析(SAX风格)期间动态导出。
7.export_simple(Content, Callback) -> ExportedFormat
Equivalent to export_simple(Content, Callback, []).
8.export_simple(Content, Callback, RootAttrs::RootAttributes) -> ExportedFormat
Types
Content = [Element]
Callback = atom()
RootAttributes = [XmlAttributes]
使用指定的回调模块导出“simple-form”XML内容。
Element is any of:
- {Tag, Attributes, Content}
- {Tag, Content}
- Tag
- IOString
- #xmlText{}
- #xmlElement{}
- #xmlPI{}
- #xmlComment{}
- #xmlDecl{}
where: - Tag = atom()
- Attributes = [{Name, Value}]
- Name = atom()
- Value = IOString | atom() | integer()
因此,标准形式的XML元素可以包含在简单形式的表示中。注意,内容列表必须是平面的。IOString是字符和/或二进制文件的列表(可能是深度列表)。
RootAttributes是一个列表: - XmlAttributes = #xmlAttribute{}
有关回调模块和根属性的详细信息,请参阅export/3。在传递回调模块之前,xml数据总是转换为正常形式。
See also: export/3, export_simple/2.
9.export_simple_content(Content, Callback) -> term()
直接导出简单的XML内容,不需要进一步的上下文。
10.export_simple_element(Content, Callback) -> term()
直接导出简单的XML元素,不需要进一步的上下文。
XMERL_XS (xmerl_xs)
Erlang与XSLT有相似之处,因为两种语言都有函数式编程方法。
概述
Erlang与XSLT有相似之处,因为两种语言都有函数式编程方法。使用xmerl_xpath可以在Erlang中编写类似于转换的XSLT。
在将XML文档转换为其他XML文档或(X)HTML以进行表示时,常常使用XSLT样式表。XSLT包含相当多的函数,学习它们可能需要一些努力。本文档假设您对XSLT有基本的了解。
由于XSLT基于带有模式匹配和递归的函数式编程方法,所以可以用Erlang编写类似的样式表。至少对于基本变换是这样的。本文档描述了如何使用XPath实现以及Erlangs模式匹配和一些函数来编写类似于转换的XSLT。
这种方法对于Erlanger来说可能更简单,但是如果您需要使用真正的XSLT样式表以“符合标准”,那么Sablotron XSLT包有一个可用的适配器,它是用c++编写的。参见教程。
定制函数
概述
XML处理器(processor)提供了许多自定义挂钩。这些挂钩被定义为函数对象,可以由调用者提供。
可以使用以下定制功能。如果它们也可以访问自己的状态变量,则该状态的访问函数在括号中标识:
- event function ( xmerl_scan:event_state/[1,2] ) (事件函数)
- hook function ( xmerl_scan:hook_state/[1,2] ) (钩子函数)
- fetch function ( xmerl_scan:fetch_state/[1,2] ) (取来函数)
- continuation function ( xmerl_scan:cont_state/[1,2] ) (附加函数)
- rules function ( xmerl_scan:rules_state/[1,2] ) (规则函数)
- accumulator function (累加器函数)
- close function (关闭函数)
对于上述所有状态访问函数,带有一个参数的函数(如event_state(GlobalState))将读取状态变量,而带有两个参数的函数(如:event_state(NewEventState, GlobalState))将对其进行修改。
对于每个函数,描述从在Option_list中指定函数的语法开始。一般的形式是{Tag, Fun}或{Tag, Fun, LocalState}。第二个表单可以用来初始化状态变量。
用户状态 (User State)
所有自定义函数都可以自由访问“用户状态”变量。当然,必须注意协调使用这种状态。建议函数使用它们自己的状态变量,因为它们实际上没有任何东西可以贡献给“全局”用户状态。另一个选项(在例如xmerl_event .erl中使用)用于自定义函数来共享一个本地状态(在xmerl_eventp中)。erl, continuation函数和fetch函数都接受cont_state。)
访问用户状态的功能:
- xmerl_scan:user_state(GlobalState)
- xmerl_scan:user_state(UserState, GlobalState)
事件函数 (Event State)
{event_fun, fun()} | {event_fun, fun(), EventState}
事件函数在已解析实体的开头和结尾调用。它的格式和语义如下:
1 | fun(Event, GlobalState) -> |
钩子函数 (Hook State)
{fetch_fun, fun()} | {fetch_fun, fun(), FetchState}
当处理器解析完一个完整的实体时,就会调用hook函数。格式和语义:
1 | fun(Entity, GlobalState) -> |
事件函数、钩子函数与累加器函数的关系如下:
1.首先使用已解析实体的“结束”事件调用事件函数。
2.调用钩子函数,可能需要重新格式化实体。
3.调用acc函数是为了(可选地)将重新格式化的实体添加到其父元素的内容中。
取来函数 (Fetch Function)
{fetch_fun, fun()} | {fetch_fun, fun(), FetchState}
调用fetch函数是为了获取外部资源(例如DTD)。
fetch函数可以响应三个不同的返回值:
1 | Result ::= |
格式和语义
1 | fun(URI, GlobalState) -> |
附加函数 (Continuation Function)
{continuation_fun, fun()} | {continuation_fun, fun(), ContinuationState}
当解析器遇到字节流结束时,将调用continuation函数。格式和语义:
1 | fun(Continue, Exception, GlobalState) -> |
规格函数 (Rules Function)
{rules, ReadFun : fun(), WriteFun : fun(), RulesState} | {rules, Table : ets()}
规则函数负责在规则数据库中存储扫描程序信息。用户提供的规则函数可以选择将信息存储在mnesia中,或者可能存储在user_state(RulesState)中。
存在以下模式:
- 如果用户没有指定一个选项,扫描器将创建一个ets表,并使用内置的函数对其读写数据。扫描完成后,ets表将被删除。
- 如果用户通过{rules, table}选项指定一个ets表,扫描程序将使用这个表。扫描完成后,它不会删除表。
- 如果用户指定读写函数,扫描器将使用它们。
读写函数的格式如下:以下是扫描仪当前正在写入的数据对象的摘要:1
2WriteFun(Context, Name, Definition, ScannerState) -> NewScannerState.
ReadFun(Context, Name, ScannerState) -> Definition | undefined.where1
2
3
4notation NotationName {system, SL} | {public, PIDL, SL}
elem_def ElementName #xmlElement{content = ContentSpec}
parameter_entity PEName PEDef
entity EntityName EntityDefNOTE: When1
2
3
4
5
6ContentSpec ::= empty | any | ElemContent
ElemContent ::= {Mode, Elems}
Mode ::= seq | choice
Elems ::= [Elem]
Elem ::= '#PCDATA' | Name | ElemContent | {Occurrence, Elems}
Occurrence ::= '*' | '?' | '+'is not wrapped with , (Occurrence = once) is implied.
累加函数 (Accumulator Function)
{acc_fun, fun()}
调用accumulator函数来累积实体的内容。在解析非常大的文件时,可能不希望这样做。在这种情况下,可以提供一个不会累积的acc函数。
请注意,甚至可以在积累之前修改已解析的实体,但这必须谨慎进行。xmerl_scan执行用于名称空间管理的元素的后处理。因此,元素必须保持其原始结构才能工作。
acc函数的格式和语义如下:
1 | %% default accumulating acc fun |
关闭函数 (Close Function)
当一个文档(主文档或外部DTD)被完全解析时,将调用close函数。当使用xmerl_scan:file/[1,2]启动xmerl_scan时,文件将被完整读取,并在解析开始之前立即关闭,因此当调用close函数时,它实际上不需要关闭文件。在这种情况下,close函数是修改状态变量的好地方。
1 | fun(GlobalState) -> |