什么是deviseXML模式的最佳实践?

作为业余软件开发人员(我还在学术界),我已经为XML文档写了几个模式。 我经常碰到devise漏洞,导致看起来丑陋的XML文档,因为我不完全确定XML的语义是什么。

我的假设:

<property> value </property> 

property = value

 <property attribute="attval"> value </property> 

具有特殊描述符的属性,属性。

 <parent> <child> value </child> </parent> 

家长有一个具有“价值”价值的特征“孩子”。

 <tag /> 

“标签”是一个标志,或者直接翻译成文本。 我不确定这一个。

 <parent> <child /> </parent> 

“孩子”描述“父母”。 “孩子”是一个标志或布尔值。 我也不确定这个。

如果你想做一些类似于表示笛卡尔坐标的东西,就会产生歧义:

 <coordinate x="0" y="1 /> <coordinate> 0,1 </coordinate> <coordinate> <x> 0 </x> <y> 1 </y> </coordinate> 

哪一个是最正确的? 根据我目前的XML模式devise的概念,我会倾向于第三个,但是我真的不知道。

简洁地描述如何有效地deviseXML模式的一些资源是什么?

看到教程:

  • Roger Costello的XML Schemas:Best Practices ”。

我也推荐:

  • Priscilla Walmsley的书“ Definitive XML Schema ”。

  • Jeni TennisonXML Schema页面

一个一般的(但是重要的)build议是不要在一个节点(不pipe是文本节点还是属性节点)中存储多个逻辑数据块。 否则,您最终需要在您通常从框架中免费获得的XMLparsing逻辑之上使用自己的parsing逻辑。

所以在你的坐标范例中, <coordinate x="0" y="1" /><coordinate> <x>0</x> <y>1</y> </coordinate>

但是<coordinate> 0,1 </coordinate>不是很好,因为它将两个逻辑数据(X坐标和Y坐标)存储在一个XML节点中,迫使用户parsing数据他们的XMLparsing器。 虽然用逗号分割string非常简单,但是如果最后还有一个额外的逗号,还会有一些含糊之处。

我同意w / cdragon的build议,以避免选项#2。 #1和#3之间的select主要是风格问题。 我喜欢使用我认为是实体属性的属性,以及我认为是数据的元素。 有时候很难分类。 尽pipe如此,也不是“错”。

虽然我们正在讨论模式devise的话题,但是我会在我的首选级别(最大)重用(包括元素和types)上添加我的两分钱,这也可以促进这些实体的外部“逻辑”引用,比方说,存储在数据库中的数据字典。

请注意,虽然“伊甸园”模式模式提供了最大限度的重用,但也涉及到大部分工作。 在这篇文章的底部,我提供了博客系列中涵盖的其他模式的链接。

伊甸园的方法 http://blogs.msdn.com/skaufman/archive/2005/05/10/416269.aspx

通过全局定义所有元素来使用模块化方法,如威尼斯盲人(Venetian Blind)方法,所有的types定义都是全局声明的。 每个元素被全局定义为节点的直接子元素,并且它的types属性可以被设置为一个指定的复合types。

 <?xml version="1.0" encoding="UTF-8"?> <xs:schema targetNamespace="TargetNamespace" xmlns:TN="TargetNamespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified"/> <xs:element name="BookInformation" type="BookInformationType"/> <xs:complexType name="BookInformationType"/> <xs:sequence> <xs:element ref="Title"/> <xs:element ref="ISBN"/> <xs:element ref="Publisher"/> <xs:element ref="PeopleInvolved" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <xs:complexType name="PeopleInvolvedType"> <xs:sequence> <xs:element name="Author"/> </xs:sequence> </xs:complexType> <xs:element name="Title"/> <xs:element name="ISBN"/> <xs:element name="Publisher"/> <xs:element name="PeopleInvolved" type="PeopleInvolvedType"/> </xs:schema> 

这种方法的优点是架构是可重用的。 由于全局定义了元素和types,所以都可以重用。 这种方法提供了可重用内容的最大数量。 缺点是模式是冗长的。 当你创build一个通用的库时,这是一个适当的devise,在这个库中,你不用担心模式元素和types的范围及其在其他模式中的使用,特别是在扩展性和模块性方面。

由于每个不同的types和元素都有一个单一的全局定义,因此这些规范的粒子/组件可以与数据库中的标识符一一对应。 虽然乍一看似乎是一个持续的人工任务,以维持文本XSD粒子/组件和数据库之间的关联,但SQL Server 2005实际上可以通过语句生成规范的模式组件标识符

 CREATE XML SCHEMA COLLECTION 

http://technet.microsoft.com/en-us/library/ms179457.aspx

相反,要从规范粒子构build模式,SQL Server 2005提供了

 SELECT xml_schema_namespace function 

http://technet.microsoft.com/en-us/library/ms191170.aspx

与math相关的非math。 (等式,坐标等)“以最简单或标准的forms” http://dictionary.reference.com/browse/canonical

其他,更容易构build,但较less结果/更“非规范化/冗余”模式模式包括

俄罗斯娃娃的方法 http://blogs.msdn.com/skaufman/archive/2005/04/21/410486.aspx

模式有一个单一的全局元素 – 根元素。 所有其他的元素和types嵌套越来越深,给它的名字,由于每个types适合在上面的一个。 由于本devise中的元素是在本地声明的,所以它们将不能通过导入或包含语句来重用。

萨拉米切片方法 http://blogs.msdn.com/skaufman/archive/2005/04/25/411809.aspx

所有元素都是全局定义的,但types定义是在本地定义的。 这样其他模式可以重用这些元素。 采用这种方法,具有本地定义types的全局元素提供元素内容的完整描述。 这个信息“切片”被单独声明,然后聚合在一起,也可以拼凑在一起构build其他模式。

威尼斯盲人方法 http://blogs.msdn.com/skaufman/archive/2005/04/29/413491.aspx

类似于俄罗斯娃娃的方法,他们都使用一个单一的全球元素。 威尼斯盲人方法通过命名和定义全局的所有types定义来描述一种模块化的方法(相对于在全局和本地types中声明元素的Salami Slice方法)。 每个全局定义的types描述一个单独的“板条”,并可以被其他组件重复使用。 另外,根据架构顶部的elementFormDefault属性设置,所有本地声明的元素可以是限定名称空间的,也可以是非限定名称空间的(可以“打开”或“closures”)。

在devise方面,XML有点主观 – 我不认为应该如何布置元素和属性有确切的指导原则,但我倾向于使用元素来表示“事物”和属性来表示单数属性/属性他们。

就坐标而言,任何一个都是完全可以接受的,但是我的倾向是用<coordinate x="" y=""/>因为它更简洁一些,如果你有许多人。

但最重要的是模式的命名空间。 确保(a)你有一个,(b)你有一个在那里的版本,所以你可以在将来改变事情,并发布一个新的版本。 版本可能是date或数字,例如

 http://company.com/2008/12/something/somethingelse/ urn:company-com:2008-12:something:somethingelse http://company.com/v1/something/somethingelse/ urn:company-com:v1:something:somethingelse 

我不知道如何deviseXML文档模型的好的学习资源(模式只是指定文档模型的正式方法)。

在我看来,XML的一个重要洞察是它不是一种语言:它是一种语法。 而每个文档模型都是一个单独的语言。

不同的文化将以各自的特殊方式使用XML。 即使在W3C规范中,您也可以在XML Schema的camelCaseNames中findXSLT的短划分名称中的Lisp和Java中的Lisp。 同样,不同的应用程序域将要求不同的XML习惯用法。

叙述文档模型(如HTML或DocBook)倾向于将可打印的文本放置在文本节点中,将元数据放入元素名称和属性中。

更多面向对象的文档模型(如SVG)几乎不使用文本节点,而只使用元素和属性。

我个人对文档模型devise的经验法则是这样的:

  • 如果是需要混合内容的免费标签汤,可以使用HTML和DocBook作为灵感来源。 其他规则只在其他方面有关。
  • 如果值将是复合或分层的,则使用元素。 XML数据应该不需要进一步parsing,除了已build立的习惯用法,例如简单空间分离的序列IDREFS。
  • 如果一个值可能需要多次出现,请使用元素。
  • 如果一个值可能需要进一步细化,或者稍后再丰富,则使用元素。
  • 如果一个值显然是primefaces的(布尔值,数字,date,标识符,简单标签),并且最多可能发生一次,那么使用一个属性。

另一种说法可能是:

  • 如果是叙述性的,它不是面向对象的。
  • 如果是面向对象的,则将对象作为元素进行build模,将primefaces属性作为属性进行build模

编辑:有些人似乎完全放弃属性。 没有什么不对 ,但是我不喜欢它,因为它膨胀了文件,使他们不必要的手工读写困难。

在devise一个基于XML的格式时,考虑一下你所代表的内容往往是好事。 尝试嘲笑一些符合您打算的目的的XML数据。 一旦你有满意的东西满足你的要求,开发模式来validation它。

在devise格式时,我倾向于使用元素来保存数据内容和属性,以便将特征应用于数据,例如id,名称,types或元素所包含数据的其他元数据。

在这方面,坐标的XML表示可能是:

 <coordinate type="cartesian"> <ordinate name="x">0</ordinate> <ordinate name="y">1</ordinate> </coordinate> 

这迎合不同的坐标系统。 如果你知道他们一直是笛卡儿,更好的实现可能是:

 <coordinate> <x>0</x> <y>1</y> </coordinate> 

当然,后者可能导致更详细的模式,因为每个元素types都需要声明(尽pipe我希望定义一个复杂的types来为这些元素实际工作)。

就像在编程中一样,通常有多种方式来实现相同的目标,但是在许多情况下没有对错,只是越来越差。 重要的是要保持一致,并尽量保持直观,以便其他人看着你的模式,他们可以理解你想要达到的目标。

您应该始终对您的模式进行版本控制,并确保针对您的模式写入的XML表示如此。 如果您没有正确的版本XML,那么在支持写入旧模式的XML的同时将模式添加到模式将会困难得多。

在我们的Java项目中,我们经常使用JAXB自动分析XML并将其转换为对象结构。 我猜对于其他的语言你会有类似的东西。 一个合适的生成器可以用你select的编程语言自动创build对象结构。 这使得XML的处理通常要容易得多,同时仍然具有用于系统之间通信的可移植XML表示。

如果你使用这样的自动映射,你会发现这限制了模式 – 除非你想要,否则<coordinate> <x> 0 </x> <y> 1 </y> </coordinate>在翻译中做特殊的魔术。 您将最终得到一个具有两个属性xy的类Coordinate ,并在架构中声明适当的types。

我被指定编写一堆XML模式来将我的公司系统与我们的客户集成在一起。 十多年前我就devise了十几个,看到规范中的很多扩展function在实际中并不能很好地工作。 在devise新的之前,我已经search了当前的最佳实践(并且到达这里!)。

上面的一些提示是有用的,但我不喜欢几乎所有的参考。 我find的devisebuild议最好的地方是来自微软。

最好的参考是XML模式devise模式:避免复杂性 。 在这里你会发现这个理智的build议:

通过理解和利用W3C XML Schema提供的有效子集的function,似乎许多模式作者将得到最好的服务,而不是试图理解语言的所有深奥和细节。

并详细解释以下指导原则:

  • 为什么你应该使用全局和本地元素声明
  • 为什么你应该使用全局和本地属性声明
  • 为什么您应该了解XML名称空间如何影响W3C XML Schema
  • 为什么你总是应该设置elementFormDefault为“合格”
  • 为什么你应该使用属性组
  • 为什么你应该使用模型组
  • 为什么你应该使用内置的简单types
  • 为什么你应该使用复杂的types
  • 为什么你不应该使用符号声明
  • 为什么你应该小心使用替代组
  • 为什么您应该对ID / IDREF的key / keyref / unique进行身份限制
  • 为什么你应该仔细使用变色龙模式
  • 为什么不应该使用默认值或固定值,尤其是对于xs:QNametypes
  • 为什么你应该使用简单types的限制和扩展
  • 为什么你应该使用复杂types的扩展
  • 为什么你应该小心使用复杂types的限制
  • 为什么你应该小心使用抽象types
  • 请使用通配符来提供明确的可扩展点
  • 不要使用组或types重新定义

我对他们build议的build议是,当他们说“谨慎使用”时 ,你应该避免这样做。 我的印象是Schema规范不是由软件开发者编写的。 他们试图使用一些面向对象的概念,但却搞得一团糟。 许多扩展机制是无用的或非常冗长的。 我真的不明白怎么有人发明复杂types的限制。

在这个网站有两个更好的文章是:

  • 模式devise模式:应对变化
  • XML模式devise模式:复杂types派生不必要?

一个普遍的技巧是用不同于正式规范的东西来指定你的模式。 放松NG看起来是最受欢迎的规格语言。 不幸的是,你将失去标准化的最好function之一。

我经常发现自己在同一个问题上挣扎,但是我发现在实践中它并不重要,XML只是数据。

也就是说,我通常更喜欢“如果说节点是一个属性,否则它是一个孩子节点”的方法。

在你的例子中,我会去:

 <coordinate> <x>0</x> <y>1</y> </coordinate> 

因为x和y是一个坐标的属性,实际上并不是说有关xml的任何内容,而是关于它所代表的对象。

我想,这取决于结构有多复杂或简单。
我会把x和y作为属性,除非x和y有自己的细节

您可以查看HTML或任何其他forms的标记(用于定义事件的XAML(如果使用WPF,MXML则使用Flash)来理解为什么某些内容被选作属性而不是子节点)

如果x和y不被重复,它们可以是属性。

让我们说坐标有多个x和y,我猜xml不允许同一名称的多个属性的节点。 在这种情况下,你将不得不使用子节点。

对于每个想要表示的值,使用元素或子元素没有任何内在的错误。

主要的考虑是有时使用属性更清洁。 由于一个元素只能有一个给定名称的属性,所以你坚持1:1的基数。 如果你将数据表示为一个子元素,你可以使用任何你想要的基数(或者打开以后再扩展)。

Rob Wells上面的回答是正确的:这取决于你要build模的关系。

任何时候显然永远不会是一对一的关系,一个属性可能会更干净。

看看你想要expression的数据的关系是我find的最好的方法。

处理笛卡尔坐标时,我发现属性表单更易于pipe理。 我的项目往往需要多个名称空间,在名称空间之间共享坐标types定义在子元素forms中变得很难看。 在子元素forms中,您必须限定子元素,在基本元素或根元素上加上命名空间,或者默认为非限定元素名称(即命名空间隐藏 )

下面是一个很好的deviseXML语法的方法列表。

如上所述,这是一个主观的实践,但是这个网站给出了一些有用的方向,比如“用这个模式解决问题X”……或者“优点和缺点是……”。