电脑爱好者,提供IT资讯信息及各类编程知识文章介绍,欢迎大家来本站学习电脑知识。 最近更新 | 联系我们 RSS订阅本站最新文章
电脑爱好者
站内搜索: 
当前位置:首页>> XML专区>>XML教程-XML数据:

XML教程-XML数据

来源:远方网络 | 2006-2-26 | (有1826人读过)

在本章中,我们将要研究一个较长的示例,用来说明一个较长的有关棒球统计和其他类似数据的列表是如何以XML格式保存的。像这样的文档有好多潜在的应用。最明显的,它可以显示在Web 页面上。还可以用作其他分析数据或是整理数据程序的输入。通过这个示例,读者将学到如何用XML来标记数据、为什么要选用XML标记、如何为文档编制CSS样式单等等内容。
本章的主要内容包括:

* 检查数据

* 数据的XML化

* XML格式的优越性

* 为文档的显示编制样式单

4.1 检查数据

当我写作这本书时(1998年10月),纽约的Yankees队在四场比赛中击败圣·迭格的Padres队,取得了24届世界系列赛的冠军。Yankees队在American League的普通赛季结束时,取得了114场胜利。总体来说,1998是一个令人赞叹的赛季。圣·路易斯Cardinals队的 Mark McGwire和芝加哥Cubs队的Sammy Sosa为了创造新的单一赛季的本垒打纪录在整个9月份展开了争夺,原来的纪录是由Roger Maris保持的。

是什么使1998赛季这样激动人心呢?玩世不恭的人会告诉你,1998是一扩展年,有三个新队加盟,因而总体上来说投手能力减弱了。这就使得著名的击球手如Sosa和McGwire以及著名的球队,如Yankees得到了出风头的机会,因为,虽然他们仍然像他们在1997年一样实力强大,但面对的对手的平均能力弱了许多。当然真正的棒球爱好者了解真正的原因,这是由于统计上的原因造成的。

这实在有点滑稽。在大多数体育项目中,我们都说过心脏、勇气、能力、技巧、决心和其他名词。但是,只有棒球爱好者需要面对这么多原始数字,如平均击球率、平均得分、平均跑垒数、平均进垒数、对左手投手的平均击球率、对右手投手的平均击球率等。

棒球爱好者都被这些数字所迷住了,数字越多越好。在每个赛季中,因特网成了成千上万的棒球爱好者的大本营,狂热的网民们在其中“管理”球队并交换球员,计算他们喜爱的球队在现实中表现的各种数字。STATS, Inc.公司跟踪了每个球员在主要联赛的赛事上的表现,因而可以计算出一个击球手是否表现得比他的平均成绩要好。在以下两节中,为了照顾对棒球不太感兴趣的读者,我们检查一下描述单个球员的击球和投球率的常用统计数字。现场统计数字也可以找到,但是我将把这些数字略去,以便将示例局限于好管理的大小。我使用的这个特殊的例子是纽约的Yankees队,对于任何队的击球手,同样的统计数字也可以得到。

4.1.1 击球手

几年前,Bruce Bukiet、Jose Palacios和我写过一篇名为A Markov Chain Approach to Baseball (用于棒球的马尔可夫链式方法)的文章(刊登在Operations Research(运筹学研究杂志),45卷第1期,1997年1-2月号,pp. 14-23, 还可在以下网址上看到这篇文章http://www.math.njit.edu/~bukiet/Papers /ball.pdf)。在这篇文章中,我们分析了1989年全国棒球联赛中的所有球队的所有可能的比赛顺序。那篇文章的结果还是比较有意思的。球队中的最坏的击球手(通常是投球手)应该是第8位出场击球的人,而不应该是第9位,至少在全国棒球联赛上是如此。但是这里我所关心的是产生那篇文章的工作。作为一个低年级的研究生,用手工算出每个球员在全国棒球联赛上的全部击球历史记录正是我的工作。如果我能够使那些数据变得像XML一样的方便,那个夏季我会过得更愉快一些的。现在,让我们将精力集中于每个球员的数据上。典型的,这种数据是以一行行的数字表示的,如表4-1所示的是1998年Yankees队的进攻队员的数据。在美国棒球联赛的比赛上,由于投球手很少击球,只有实际上击球的队员才列在表中。

每一列有效地定义了一个元素。因而就需要为球员、位置、进行的比赛、击球、跑垒、击球数、两垒、三垒、本垒打、跑入和步行等建立元素。单垒通常都不单独报告。这个数据是从总击打数中减去双垒、三垒和本垒打的总和后得到的。

表4-1 The 1998年Yankees队的进攻队员数据

Name

Postion

Game Played

At

Bats

Runs

Hits

Doubles

Triples

Home

Runs

Runs

Batted

In

Strike

Walks

Outs

Hit

by Pitch

Scott Brosius

Third

Base

152

530

86

159

34

0

19

98

52

97

10

Homer Bush

Second BBase

45

71

17

27

3

0

1

5

5

19

0

Chad Curtis

Outfield

151

456

79

111

21

1

10

56

75

80

7

Chili Davis

Designated

Hitter

35

103

11

30

7

0

3

9

14

18

0

Mike Figga

catcher

1

4

1

1

0

0

0

0

0

1

0

Joe Girardi

catcher

78

254

31

70

11

4

3

31

14

38

2

Derek Jeter

Shortsho

149

626

127

203

25

8

19

84

57

119

5



Chuck

Knoblauch

Second Base

150

603

117

160

25

4

17

64

76

70

 



Ricky Ledee

Outfield

42

79

13

19

5

2

1

12

7

29

0



Mike Lowell

Third Base

8

15

1

4

0

0

0

0

0

1

0



Tino Martinez

First Base

142

531

92

149

33

1

28

123

61

83

6



Paul O'Neill

Outfield

152

602

95

191

40

2

24

116

57

103

2



Jorge Posada

catcher

111

358

56

96

23

0

17

63

47

92

0



Tim Raines

Outfield

109

321

53

93

13

1

5

47

55

49

3



Luis Sojo

Shortshop

54

147

16

34

3

1

0

14

4

15

0



Shane Spencer

Outfield

27

67

18

25

6

0

10

27

5

12

0



Darryl

Strawberry

Designated

Hitter

101

295

44

73

11

2

24

57

46

90

3



Dale Sveum

First Base

30

58

6

9

0

0

0

3

4

16

0



Bernie Williams

Outfield

128

499

101

169

30

5

26

97

74

81

1



译者注:棒球数据不过是一种演示。在棒球统计数据的XML文档中,由于使用的是英文专用名词,故这里未翻译成中文。如果翻译过来反而无法相互对照。表4-2也同样处理。

前面表中的数据和下一节中的投球手数据都是加以限制后的列表,只是用来表明在一个典型的棒球赛中收集的数据。除了列出的以外,还有许多其他数据没有在这里列出。我打算使用这些基本信息,以便使示例容易管理。

4.1.2 投球手

人们并不指望投球手成为全垒跑的击球手或是偷袭能手。确实偶尔到达第一垒的投球手是对一个队的意外奖励。对投球手的评价要根据表4-2中列出的全场的不同种类的数字。这个表的每列也定义了一个元素。这些元素中的一部分,如姓名和位置对于投球手和击球手都是有的。其他元素如解救(saves)和成功防守(shutouts)只适用于投球手。还有几个,如得分(runs)和全垒跑(home runs)与击球手统计中的名称相同,但是具有不同意义。例如,击球手的得分数是击球手获得的分数。而对于投球手来说,是指对方在这个投球手下得到的分数。

4.1.3 XML数据的组织

XML是建立在容器模型的基础之上的。每个XML元素可以包含文本或是称为子元素的其他XML元素。有几个XML元素既可以包含文本也可以包含子元素。虽然通常来说,这并不是一种好形式,是应该尽量避免的。

不过,常常有不止一种组织数据的方法,这要取决于需要。XML的一个好处是,它使得编写程序来以不同形式组织数据变得相当直接。在第14章我们讨论XSL变换时还要讨论这一问题。

作为开始,必须注意的第一个问题是什么包含什么?例如,相当明显的是,联赛包含分部,分部包含球队,球队又包含球员,而球员又可在指定的时间进行交易,每个球员必定属于一个球队,每个球队又必定属于一个分部。类似的,一个赛季包含许多场比赛,每场比赛又包含几局,而局又包含击球阶段,击球阶段又包含投球阶段。

但是,赛季包括联赛吗或是联赛包括赛季吗?这个问题就不是很明显。确实对这样的问题没有唯一的答案。将赛季元素定义为联赛元素的子元素还是将联赛元素变为赛季元素的子元素有更多的意义,这要依赖于数据要用来干什么。用户甚至可以创建新的既包含赛季也包含联赛的根元素,哪个元素也不是另外元素的子元素(虽然要有效地这样做,还需要某些先进的技术,在以下几章还讨论不到这些技术)。用户可按用户的意愿来组织数据。

表4-2 1998年Yankees队的投球手

Name

P

W

L

S

G

GS

CG

SHO

ERA

IP

H

HR

R

ER

HB

WP

BK

WB

SO

Joe

Borowski

Relief Pitcher

1

0

0

8

0

0

0

6.52

9.2

11

0

7

7

0

0

0

4

7

Ryan Bradley

Relief Pitcher

2

1

0

5

1

0

0

5.68

12.2

12

2

9

8

1

0

0

9

13

Jim Bruske

Relief Pitcher

1

0

0

3

1

0

0

3

9

9

2

3

3

0

0

0

1

3

Mike Buddie

Relief Pitcher

4

1

0

24

2

0

0

5.62

41.2

46

5

29

26

3

2

1

13

20

David Cone

Starting Pitcher

20

7

0

31

31

3

0

3.55

207.2

186

20

89

82

15

6

0

59

209

Todd Erdos

Relief Pitcher

0

0

0

2

0

0

0

9

2

5

0

2

2

0

0

0

1

0

Orlando Hernandez

Starting Pitcher

12

4

0

21

21

3

1

3.13

141

113

11

53

49

6

5

2

52

131

Darren Holmes

Relief Pitcher

0

3

2

34

0

0

0

3.33

51.1

53

4

19

19

2

1

0

14

31

Hideki Irabu

Starting Pitcher

13

9

0

29

28

2

1

4.06

173

148

27

79

78

9

6

1

76

126

Mike Jerzembeck

Starting Pitcher

0

1

0

3

2

0

0

12.79

6.1

9

2

9

9

0

1

1

4

1

Graeme Lloyd

Relief Pitcher

3

0

0

50

0

0

0

1.67

37.2

26

3

10

7

2

2

0

6

20

Ramiro Mendoza

Relief Pitcher

10

2

1

41

14

1

1

3.25

130.1

131

9

50

47

9

3

0

30

56

Jeff Nelson

Relief Pitcher

5

3

3

45

0

0

0

3.79

40.1

44

1

18

17

8

2

0

22

35

Andy Pettitte

Starting Pitcher

16

11

0

33

32

5

0

4.24

216.1

226

20

10

2

6

5

0

87

146

Mariano Rivera

Relief Pitcher

3

0

36

54

0

0

0

1.91

61.1

48

3

13

13

1

0

0

17

36

Mike Stanton

Relief Pitcher

4

1

6

67

0

0

0

5.47

79

71

13

51

48

4

0

0

26

69

Jay Tessmer

Relief Pitcher

1

0

0

7

0

0

0

3.12

8.2

4

1

3

3

0

1

0

4

6

David Wells

Starting Pitcher

18

4

0

30

30

8

5

3.49

214.1

195

29

86

83

1

2

0

29

163



熟悉数据库理论的读者可能会将XML模型看作为分支型的数据库,因而也就认为与分支数据库具有同样的缺点(和少数优点)。许多时候以表为基础的关系型方法更有实际意义。在本例中,也属于有实际意义的情况。但是,XML并不遵循关系模型。

4.2 数据的XML化

让我们用XML处理1998年的Major

League赛季数据的标记开始。请记住,在XML内,允许我们创建标记。我们已经决定,文档的根元素是赛季(season)。赛季包括联赛(leagues),而联赛包括分部(divisions),分部又包括球队(teams),球队包括队员(players)。队员的统计数字包括参加的场数(games

played)、击球次数(at

bats)、得分数(runs)、击中数(hits)、双垒(doubles)、三垒(triples)、全垒得分(home

runs)、击球得分(runs batted in)、走步数(walks)和被投手击中数(hits by pitch)。

4.2.1 开始编写文档:XML声明和根元素

XML文档可由XML声明加以识别。这是放在所有XML文档的开头的一条处理指令,标识正在使用的XML版本。当前可理解的唯一版本号是1.0。



<?xml version="1.0"?>





每个合格的XML文档(所谓合格有特定的意义,这将在下一章中加以讨论)必须有一个根元素。这是一个完全包括文档中其他所有元素的元素。根元素的起始标记要放在所有其他元素的起始标记之前,而根元素的结束标记要放在所有其他元素的结束标记之后。对于我们的根元素SEASON,其起始标记是,而结束标记是。文档现在看起来像下面的样子:





<?xml version="1.0"?>

<SEASON>

</SEASON>





XML声明既不是元素也不是标记。它是处理指令。因而不需要将声明放在根元素SEASON之内。但是,我们在文档中放入的每个元素都得放在起始标记和结束标记之间。



根元素的这种选择方法说明我们已经不能在一个文件中保存多个赛季的数据了。如果想要保存多个赛季的数据的话,可以定义一个新的包括赛季(seasons)的根元素,例如,





<?xml version="1.0"?>

<DOCUMENT>

<SEASON>

</SEASON>

<SEASON>

</SEASON>

</DOCUMENT>





命名约定

在开始之前,我还要说几句关于命名约定的话。正如我们在下一章中所见到的,XML的元素名是比较灵活的,可以包括任意数目的字母和数字,既可是大写的也可是小写的。可以将XML标记写成下面的任何样子:





<SEASON>

<Season>

<season>

<season1998>

<Season98>

<season_98>





这就会有成千上万种可能的变化。全使用大写、全使用小写或是混合大小写都是可以的。但是,我推荐使用一种约定,并坚持下去。

当然,我们对所谈到的赛季加以标识。为达此目的,可为SEASON元素定义一个名为YEAR的子元素。例如:



<?xml version="1.0"?>

<SEASON>

<YEAR>

1998

</YEAR>

</SEASON>





我在此处以及其他例子中使用了缩进,以便指明元素YEAR是元素SEASON的子元素,而文本1998是元素YEAR的内容。这是一种很好的编程习惯,但这不是必须的。XML中的空白没有特殊的意义。同样的例子也可写成下面的样子:





<?xml version="1.0"?>

<SEASON>

<YEAR>1998</YEAR>

</SEASON>





确实,我经常将元素压缩到一行上(当一行上可以放得下,而空间又比较紧张时)。还可以将文档再加以压缩,即使压缩成一行也可以,但这要失去可读性。例如:



<?xml version="1.0"?><SEASON><YEAR>1998</YEAR></SEASON>





当然这样的文档是比较难以阅读和理解的,这也就是为什么我没有这样书写的原因。XML 1.0规范中的第十条目的中写道:"Terseness in XML

markup is of minimal importance."翻译成中文是,"XML标记中的简捷性是不太重要的。"棒球示例完全反映出了这个目的。

4.2.2 联赛(League)、(分部)Division和(球队)Team数据的XML化

主要棒球联赛分成两个联赛:American League和National League。每个联赛都有名称。两个名称可如下编码:



<?xml version="1.0"?>

<SEASON>

<YEAR>1998</YEAR>

<LEAGUE>

<LEAGUE_NAME>National League</LEAGUE_NAME>

</LEAGUE>

<LEAGUE>

<LEAGUE_NAME>American League</LEAGUE_NAME>

</LEAGUE>

</SEASON>



我在这里将联赛的名称定义为元素LEAGUE_NAME,而不是简单的NAME元素。因为NAME太普遍了,而且还打算将其用在其他场合。例如,分部、球队和球员都有名称。



带有相同的名称的不同领域的元素可以利用命名域(namespaces)结合在一起。命名域的问题将在第18章中加以讨论。但是,即使使用命名域,也不要将同一领域(如本例中的TEAM和LEAGUE)的多个术语给予同样的名称。



每个联赛可分为东部(east)、西部(west)和中部(central)分部,可编码如下:



<LEAGUE>

<LEAGUE_NAME>National League</LEAGUE_NAME>

<DIVISION>

<DIVISION_NAME>East</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>Central</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>West</DIVISION_NAME>

</DIVISION>

</LEAGUE>

<LEAGUE>

<LEAGUE_NAME>American League</LEAGUE_NAME>

<DIVISION>

<DIVISION_NAME>East</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>Central</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>West</DIVISION_NAME>

</DIVISION>

</LEAGUE>





元素的实际值依赖于包括该元素的父元素。American League和National League都有East分部,但是这不是一回事。

每个分部又分为多个球队。每个球队都有一个队名和城市名。例如,与American League联赛East分部有关的名称可编码如下:



<DIVISION>

<DIVISION_NAME>East</DIVISION_NAME>

<TEAM>

<TEAM_CITY>Baltimore</TEAM_CITY>

<TEAM_NAME>Orioles</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>Boston</TEAM_CITY>

<TEAM_NAME>Red Sox</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>New York</TEAM_CITY>

<TEAM_NAME>Yankees</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>Tampa Bay</TEAM_CITY>

<TEAM_NAME>Devil Rays</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>Toronto</TEAM_CITY>

<TEAM_NAME>Blue Jays</TEAM_NAME>

</TEAM>

</DIVISION>

4.2.2 联赛(League)、(分部)Division和(球队)Team数据的XML化

主要棒球联赛分成两个联赛:American League和National League。每个联赛都有名称。两个名称可如下编码:



<?xml version="1.0"?>

<SEASON>

<YEAR>1998</YEAR>

<LEAGUE>

<LEAGUE_NAME>National League</LEAGUE_NAME>

</LEAGUE>

<LEAGUE>

<LEAGUE_NAME>American League</LEAGUE_NAME>

</LEAGUE>

</SEASON>





我在这里将联赛的名称定义为元素LEAGUE_NAME,而不是简单的NAME元素。因为NAME太普遍了,而且还打算将其用在其他场合。例如,分部、球队和球员都有名称。



带有相同的名称的不同领域的元素可以利用命名域(namespaces)结合在一起。命名域的问题将在第18章中加以讨论。但是,即使使用命名域,也不要将同一领域(如本例中的TEAM和LEAGUE)的多个术语给予同样的名称。



每个联赛可分为东部(east)、西部(west)和中部(central)分部,可编码如下:



<LEAGUE>

<LEAGUE_NAME>National League</LEAGUE_NAME>

<DIVISION>

<DIVISION_NAME>East</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>Central</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>West</DIVISION_NAME>

</DIVISION>

</LEAGUE>

<LEAGUE>

<LEAGUE_NAME>American League</LEAGUE_NAME>

<DIVISION>

<DIVISION_NAME>East</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>Central</DIVISION_NAME>

</DIVISION>

<DIVISION>

<DIVISION_NAME>West</DIVISION_NAME>

</DIVISION>

</LEAGUE>





元素的实际值依赖于包括该元素的父元素。American League和National League都有East分部,但是这不是一回事。

每个分部又分为多个球队。每个球队都有一个队名和城市名。例如,与American League联赛East分部有关的名称可编码如下:



<DIVISION>

<DIVISION_NAME>East</DIVISION_NAME>

<TEAM>

<TEAM_CITY>Baltimore</TEAM_CITY>

<TEAM_NAME>Orioles</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>Boston</TEAM_CITY>

<TEAM_NAME>Red Sox</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>New York</TEAM_CITY>

<TEAM_NAME>Yankees</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>Tampa Bay</TEAM_CITY>

<TEAM_NAME>Devil Rays</TEAM_NAME>

</TEAM>

<TEAM>

<TEAM_CITY>Toronto</TEAM_CITY>

<TEAM_NAME>Blue Jays</TEAM_NAME>

</TEAM>

</DIVISION>


XML专区热门文章排行
网站赞助商
购买此位置

 

关于我们 | 网站地图 | 文档一览 | 友情链接| 联系我们

Copyright © 2003-2024 电脑爱好者 版权所有 备案号:鲁ICP备09059398号