7.3.2 用 XML 表示文档

XML 格式非常流行,非常适合于保存分层次的数据,比如,上一节的文档。如何处理 XML,对于许多实际应用非常重要,因此,在这一节,我们要扩展我们的应用程序,以支持从 XML 文件加载文档。我们将使用.NET 3.5 的 LINQ to XMLAPI 完成大部分的困难工作,自己再写另外的 XML 解析器没有任何意义。LINQto XML 是函数概念应用于主流框架的很好示例:虽然它不是纯粹的函数式 API(类型一般是可变的),但是对象能够以递归和声明的形式构造,这就使代码的结构一目了然,因此,比使用 DOM
API 的传统代码更容易理解。

在某种意义上,这是数据从一种表示到另一种表示的再次转换。这次,源表示是 LINQ to XML 对象的结构,目标是我们 7.3.1 节的文档数据类型。这次的转换更容易,因为两种数据结构都是分层次的。清单 7.11 是用 XML 格式表示的文档。

清单 7.11 XML 表示的样本文档 (XML)

<titled title="FunctionalProgramming for the Real World"

font="Cambria"size="18" style="bold">

<splitorientation="vertical">

<imagefilename="C:\Writing\Functional\Cover.jpg" />   | 把子部分保存为

<text>In thisbook, we‘ll introduce you (...)</text>       | 嵌套的 XML 元素

</split>

</titled>

在看到转换的核心之前,我们需要实现一些工具函数,解析在 XML 中显示的特性值;特别是,我们需要解析字体名和 SplitPart方向的函数。清单 7.12 显示了这些函数,并引入了几个LINQ to XML 库的对象。

清单 7.12 使用 LINQ to XML 解析字体和方向 (F#)

open System.Xml.Linq

let attr(node:XElement, name, defaultValue)=   [1]

let attr =node.Attribute(XName.Get(name))

if (attr <> null) thenattr.Value else defaultValue  <-- 如果没有,就返回默认值

let parseOrientation(node) =   [2]

match attr(node,"orientation", "") with

| "horizontal" –>Horizontal

| "vertical" –>Vertical

| _ -> failwith "Unknownorientation!"  <-- 抛出异常

let parseFont(node) =   [3]

let style = attr(node,"style", "")

let style =

matchstyle.Contains("bold"), style.Contains("italic") with

| true, false ->FontStyle.Bold

| false, true ->FontStyle.Italic

| true, true ->FontStyle.Bold ||| FontStyle.Italic  <-- 组合两个 .NET 枚举值

| false, false ->FontStyle.Regular

let name = attr(node,"font", "Calibri")

new Font(name, float32(attr(node,"size", "12")), style)

这段代码将只引用了System.Xml.dll 和System.Xml.Linq.dll 程序集。在 Visual Studio 中,通常可以从解决方案资源管理器中,用添加引用命令实现;在 F# Interactive 中,可以使用 #r"..." 指令,参数值指定程序集的路径,如果程序集在全局程序集缓存(GAC)中,只要指定名称就行了。

清单开头的 attr 函数[1],用于读特性,第一个参数是 XElement(LINQ to XML 类型,表示 XML 元素),后面特性的名字,最后一个参数是默认值,当没有这个特性时使用。第二个函数[2]使用 attr 读取传入的 XML 节点中 orientation 特性的值。如果特性包含的不是希望的值,函数将使用标准的 F#failwith 函数,抛出异常。

parseFont [3]用于把 XML 标记的特性,像清单 7.11中的标题,转换成 .NET 中的 Font 对象。最有意义的部分是解析 style 特性,检查特性值是否包含两个字符串(bold 和 italic),作为子字符串,然后,使用模式匹配为四种可能性中的每一个指定样式。这个函数还使用 float32 转换函数,把表示大小的字符串转换成数字,然后创建 Font 实例。

我们已经有了需要的所有工具函数,因此,加载 XML 文档就很容易了。清单7.13 显示了递归函数loadPart,实现全部转换。

清单 7.13从 XML 中加载文档 (F#)

let rec loadPart(node:XElement) =

match node.Name.LocalName with   [1]

| "titled" –>

let tx = { Text =attr(node, "title", ""); Font = parseFont node}

let body =loadPart(Seq.head(node.Elements()))  <-- 递归加载第一个子元素

TitledPart(tx,body)

| "split" ->

let orient =parseOrientation node

let nodes =node.Elements() |> List.ofSeq |> List.map loadPart   <-- 递归加载所有子元素

SplitPart(orient,nodes)

| "text" ->

TextPart({Text =node.Value; Font = parseFont node})

| "image" ->

ImagePart(attr(node,"filename", ""))

| name -> failwith("Unknownnode: " + name)  [2]

函数的参数为 XML 元素,我们在以后使用时,我们把 XML 文档的根元素给它。函数主体是一个 match构造[1],依据已知的选项检查元素的名称,如果遇到未知的标记[2],就抛出异常。

加载图像和文本部分很容易,因为我们只要使用工具函数,读取特性,并创建相应的 DocumentPart 值。其余两个文档部分类型涉及递归,因此更重要。

要从 titled 元素创建 TitledPart,首先要解析标题文本的特性,然后,递归处理这部分中的第一个 XML 元素。读取第一个子元素,我们调用 Elements() 方法,它以 .NET IEnumerable 集合的形式返回所有子元素。在 F# 中,IEnumerable<T> 简称为 seq<‘a>,因此,可以使用 Seq 模块中的函数来处理,它类似于处理列表的函数。在我们的示例中,我们使用Seq.head,返回集合中的第一个元素(头)。如果我们用 C# 写代码,可以调用Elements().First()
来达到同样的效果。

从 split 元素创建 SplitPart,需要解析所有子元素,因此,我们再次调用 Elements() 方法,但这一次,我们把结果转换为XElement 值的函数式列表。我们递归地把每个元素转换成 DocumentPart 值,使用映射,把 loadPart 函数作为参数值。

这个函数非常简单,因为它只用几行代码,就能为每个受支持的标记解析 XML 节点。之所以这样简单,是因为 XML 文档的分层次,与目标表示形式的方式相同,这样,一个部分有嵌套的子部分时,能够使用递归。

最后,我们会看到应用程序如何显示大文档:在 XML 编辑器中设计文档,比在 F#中创建值更容易。清单7.14 显示了最后的组装,把目前为止我们已经开发的所有代码组合成通常的 Windows 窗体应用程序。

清单 7.14 把应用程序的所有部分组织到一起 (F#)

open System.Windows.Forms

[<System.STAThread>]

do

let doc =loadPart(XDocument.Load(@"..\..\document.xml").Root)

let bounds = { Left = 0.0f; Top =0.0f; Width = 520.0f; Height = 630.0f }

let parts = documentToScreen(doc,bounds)

let img = drawImage (570, 680) 25.0f(drawElements parts)

let main = new Form(Text ="Document", BackgroundImage = img,

ClientSize = Size(570, 680))

Application.Run(main)

代码首先使用XDocument 类,从 XML 文件加载文档。我们把文档的根元素传递给 loadPart 函数,进行文档分层次表示的转换;接下来,我们使用documentToScreen,将它转换成平面表示,然后,使用我们在清单 7.8 中看到的代码,绘制并显示文档。我们还添加了 STAThread 特性,这是独立的 Windows 窗体应用程序所必需的。最后一行,用 Application.Run 方法,启动应用的程序。图 7.4 显示运行的结果。

图 7.4 最终完成的应用程序,显示更复杂的文档,有四种文档部分

我们提到过,文档的分层次表示对于文档的初始构造和操作,都是有用的。现在,我们就来看一看。

时间: 2024-11-03 11:28:49

7.3.2 用 XML 表示文档的相关文章

maven工程web层的web.xml配置文档内容

下面是web层,web.xml配置文档里面需要配置的东西: 1.lo4j配置 2.读取spring文件配置 3.设计路径变量值 4.spring字符集过滤器 5.登陆过滤器 6.springMVC核心配置 7.session过期时间 8.错误页面跳转 以下是实例: <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSch

xml约束文档之DTD

DTD XML约束文档 文档类型定义(DTD)可定义合法的XML文档构建模块,它使用一系列合法的元素来定义文档的结构.DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用 . 1.内部声明文档 <?xml version="1.0"?> <!DOCTYPE note [ <!ELEMENT note (to,from,heading,body)> <!ELEMENT to      (#PCDATA)> <!ELEMENT fr

XML 存储文档

package com.kpsh.myself; import java.io.File;import java.io.FileWriter; import org.dom4j.Document;import org.dom4j.DocumentHelper;import org.dom4j.Element;import org.dom4j.io.XMLWriter; public class ParseXML {   public static void main(String[] args)

PHP解析XML格式文档

<?php// 首先要建一个DOMDocument对象$xml = new DOMDocument();// 加载Xml文件$xml->load("3.xml");// 获取所有的post标签$postDom = $xml->getElementsByTagName("PROPERTIES");print_r($postDom);echo '<br>';// 循环遍历post标签    foreach($postDom as $post

xml.dom——文档对象模型API

文档对象模型,或者"DOM",是一个跨语言API的World Wide Web Consortium(W3C)来访问和修改XML文档.DOM的实现提供了一个XML文档树结构,或允许客户机代码从头开始建立这样一个结构.然后给访问结构通过一组对象提供著名的接口. 模块内容 xml.dom包含以下功能: xml.dom.registerDOMImplementation(name,factory) 注册factory函数名称的名称.factory函数应该返回一个对象实现 DOMImpleme

tomcat web.xml的文档类型声明

Servlet 2.2 2.3所使用的文档类型为dtd文件 Servlet 2.4所使用的文件为xsd文件 <web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="ht

xml的文档声明

1.1.1 Xml文件的组成部分文档声明元素元素的属性注释CDATA区特殊字符处理指令(PI:Processing Instruction):了解绿色标注的内容:不作为掌握,了解即可1.1.2 文档声明什么是文档声明?在编写XML文档时,需要先使用文档声明来声明XML文档.且必须出现在文档的第一行这就好比我们在写java文件的时候需要声明class一样, 就是个硬性的规定.如何编写文档声明? <?xml version='1.0' encoding='UTF-8'?> xml表示标签的名字 v

html4.0.1,h5,xml,文档声明区别

<!DOCTYPE> 声明不是 HTML 标签:它是指示 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令. 提示:请始终向 HTML 文档添加 <!DOCTYPE> 声明,这样浏览器才能获知文档类型. 在 HTML 4.01 中,<!DOCTYPE> 声明引用 DTD,因为 HTML 4.01 基于 SGML.DTD 规定了标记语言的规则,这样浏览器才能正确地呈现内容. HTML5 不基于 SGML,所以不需要引用 DTD. 在 HTML 4.01 中有三

C#实体类生成XML与XML Schema文档

一.实体类生成XML 1 private void CreateXML() 2 { 3 Type[] objType = DBEntityRegst(); 4 foreach (var item in objType) 5 { 6 if (item == null) 7 { 8 break; 9 } 10 11 XmlDocument doc = new XmlDocument(); 12 13 //<?xml version="1.0"?> 14 XmlDeclarati