我喜欢把XML形象地称为“数据库”,因为它为游戏提供了大量数据。一个数据包含其名字(参数名)和内容(参数)。每个参数名都在程序中被声明和应用,用简单易懂的话来说,就是我们必须按照程序给出的数据来制作。如果使用了一个程序中不存在的参数名,便会在进入游戏时报错,这点我们会在后期归纳报错时详细讲解。而数据的内容则按照一定的类型去完成,不符合类型地去填写内容往往会报错。若一个数据被程序提及,却没有被数据库提及,则使用程序给出的默认值。
【注:这里的参数名其实被称为“标记”,每一个键值对被称为一个元素,但为了方便新手理解,我不引入相关的专业名词】
每一个XML文件的第一行必定为
<?xml version="1.0" encoding="utf-8"?>
是XML文件的识别码。
①文本式编辑
基本格式为:
<参数名>参数</参数名>
这里就像一个前后括号包着一个东西,所以需要十分注意“后括号”的"/"字符。我们称这种参数是一个简单的值的类型为“基础类型”。部分数据的参数不是简单的一个值,而可能由其他数据组成,形成“复合式”甚至“嵌套式”的结构,这是因为它们的类型为“复合类型”。
<大参数名>
<子参数A>A</子参数A>
<子参数B>B</子参数B>
</大参数名>
<大参数名>
<子参数C>C</子参数C>
<子参数D>
<孙参数>孙</孙参数>
</子参数D>
</大参数名>
有极少数情况,我们不需要参数:
<参数名></参数名>
此时可以简写为:
<参数名/>
有时,在参数名处可以加上一些游戏预设的记号,此时请把记号置于前面的参数名处,格式为 记号名="记号内容" ,例:
<参数名A Inherit="False">a</参数名A>
【注:“记号”在XML中学术译名为属性】
②.注释
注释写法为<!--注释内容-->,可以换行:
<!--
啊对对对
-->
不允许嵌套,如这么做是要报错的:
<!--
<!--啊错错错-->
-->
③List结构
在复合结构中,有一种特殊的数据类型(以后我会以“List类型”来形容它)。正常的复合结构,一个大数据所包括的小数据,每一个数据仅对应一个值。给一个数据对应多个值,或一个大数据内出现多次同一个数据是不被允许的,而List则能够解决这一问题。此处给出一个“人际关系”的例子,其中基础类型的参数,类型均为字符串,希望填写一个称呼,
<人际关系>
<妻子>夫人</妻子>
<孩子>大儿子,二儿子</孩子>
</人际关系>
显然是错误的,程序会认为有一个孩子被称为“大儿子,二儿子”
==========================
<人际关系>
<妻子>夫人</妻子>
<孩子>大儿子</孩子>
<孩子>二儿子</孩子>
</人际关系>
“孩子”出现了两次,会导致程序报错
=========================
可能可以用这种方式解决:
<人际关系>
<孩子A>大儿子</孩子A>
<孩子B>二儿子</孩子B>
</人际关系>
问题就在于,每多一个孩子,程序就要多规定一个新数据
=========================
List类似一堆同类型数据的有序集合体,能够让“一个”数据有“多个内容”。于是,若把“孩子”的类型设为“List类型”后:
<人际关系>
<妻子>夫人</妻子>
<孩子>
<li>大儿子</li>
<li>二儿子</li>
</孩子>
</人际关系>
此处的“孩子”显然成为了一个复合结构。其中每一个“li”数据被称为一个“元素”。事实上,这种元素可以被不断添加进list当中。
List结构是允许嵌套的,下面是一段疯狂的代码:
<list>
<li>
<li>文</li>
<li>化</li>
<li>有</li>
<li>限</li>
</li>
<li>
<li>公</li>
<li>司</li>
</li>
</list>
在mod制作中,数据类型由程序决定,xml作为一个数据库是没有办法修改的。制作者们不能自行将一个数据变为List类型,也不能以简单类型的方式来写一个List。在日后的学习过程中,我会给出它们的类型,需要仔细辨认。
<list><li>A</li></list>
单元素的list通常这么写,也可以换行
④父对象关系:ParentName,Name,Inherit记号
数据库里有这堆东西:
<人们>
<人>
<称呼>父亲</称呼>
<年龄>47</年龄>
<单位>文化有限公司</单位>
<地址>蒸汽社区</地址>
<姓>郑</姓>
</人>
<人>
<称呼>儿子</称呼>
<年龄>23</年龄>
<地址>蒸汽社区</地址>
<姓>郑</姓>
</人>
</人们>
我们会发现儿子与父亲有许多相同点:地址和姓。而如果父子间的相同点越来越多,或出现了二儿子,三儿子等,一些相同的数据就会重复的出现。而我们想修改这个“家族”的姓时又要全翻一遍来修改。事实上,儿子的部分数据应当永远与父亲相同。
我们使用“父对象”来实现这种“继承”的功能:
<人们>
<人 Name=”爹”>
<称呼>父亲</称呼>
<年龄>47</年龄>
<单位>文化有限</单位>
<地址>蒸汽社区</地址>
<姓>郑</姓>
</人>
<人 ParentName=”爹”>
<称呼>儿子</称呼>
<年龄>23</年龄>
<单位 Inherit=”False”/>
</人>
</人们>
前面提到过,一个未被数据库提及的数据将被视为默认值。在此处,由于“儿子”未提及“地址”与“姓”,且其继承了“爹”的数据,所以“地址”和“姓”就会直接被视为是“父亲”的“地址”和“姓”,而儿子自己本身具有的“称呼”和“年龄”,这两个数据将直接覆盖其父对象的对应数据;特别的,此处的“单位”数据没有对应的参数,而是使用了“Inherit=false”标签,表示该数据不继承父对象。
从上不难得出使用方法:
Name=”A”,ParentName=”A”
其中,整个数据库仅允许出现一个被命名为A的Name,其所标记的数据体就是一个父对象;而所有被标记为ParentName=”A”的数据体都将以被Name=”A”标记的为父对象。显然,一个数据体不允许将自己视为自己的父对象,但继承关系是允许被逐级嵌套的:
<人们>
<人 Name=”一代目”>
<称呼>爷</称呼>
<姓>郑</姓>
<地址>天地</地址>
</人>
<人 ParentName=”一代目”,Name=”二代目”>
<称呼>爹</称呼>
<地址>蒸汽社区</地址>
</人>
<人 ParentName=”二代目”>
<称呼>崽种</称呼>
</人>
</人们>
输出第三代人的信息,姓氏会直接继承“一代目”的姓,而地址则继承更近的“二代目”,大家可以自行分析。
特别地,当某个数据体中存在复合数据时,将会全部拆到基础类型,而不会把复合数据视为整体:
<信息表>
<信息卡 Name=”卡”>
<代号>A</代号>
<内容>
<工资>14000</工资>
<年终>2000</年终>
<五险一金>1000</五险一金>
</内容>
</信息卡>
<信息卡 ParentName=”卡”>
<代号>B</代号>
<内容>
<工资>9000</工资>
</内容>
</信息卡>
</信息表>
这里的“内容”作为一个复合数据,将会被拆分为多个数据来分别继承(如果拆出来的也有复合那么继续拆直到全为基础),所以B实际上的内容为{工资:9000,年终:2000,五险一金:1000},如果希望B的内容仅为{工资:9000},那么应当对“内容”使用Inherit记号。这样一来,其余两项就会因没有被数据库提及而使用默认值。
List类型由于其特殊的有序性,在继承时会按序合并父对象与子对象的数据内容。