为什么在XML中节点顺序很重要?

10
我最近在处理一个API,它要求XML文档的节点以特定顺序出现。我不明白为什么他们要强制执行这一点,因为我找不到任何理由支持这样做。
例如,以下内容是正确的(XML已大大简化):
<transaction>
    <address>1 main st</address>
    <amount>100</amount>
    <orderId>1234</orderId>
</transaction>

但是这样会返回一个错误。
<transaction>
    <address>1 main st</address>
    <orderId>1234</orderId>
    <amount>100</amount>
</transaction>

起初我认为这样做是为了让他们能够以列表/数组形式存储物品,并且使索引始终指向相同的节点。我明白为什么按照相同顺序发送具有相同名称的兄弟节点很重要,正如此问题中所解释的那样。然而,某些节点可以被省略:

<transaction>
    <amount>100</amount>
    <orderId>1234</orderId>
</transaction>

因此,在第三个示例中,amount和orderId现在将位于[0]和[1]而不是在第一个(正确)示例中的[1]和[2]。

另一种想法是他们将XML作为字符串处理,并要求他们始终知道哪些节点在彼此之后出现,但由于允许省略节点,因此这种理论没有意义。

有人能向我解释为什么我给出节点的顺序很重要吗?或者我只是在与一个古老而沮丧的API打交道?


2
我不理解这里的负投票或关闭投票。 - John Saunders
5个回答

20

在这样的XML中,节点顺序显然很重要:

<p>
   <span>This wouldn't make much sense</span>
   <span>if the order of these nodes were reversed.</span>
</p>

在你提供的XML中,这种情况不太明显,它似乎是某种序列化格式。但是,如果属性没有按正确顺序设置,则具有副作用的属性设置器的对象可能会失败。
想象一个具有私有Person字段的类,该类公开PersonID和Name属性。PersonID setter创建了私有Person实例,而Name setter设置了私有Person字段上的Name属性。在这种情况下,在设置PersonID之前设置Name会失败,因为Person尚不存在。
在这种情况下,实施要求PersonID在XML中出现在Name之前的模式可以防止发生此错误,但代价是强制其他开发人员执行看似无意义的操作。
在这种情况下,显而易见的做法是找到编写该类的开发人员并打他一顿。虽然这很少可能,但思考一下在这种情况下可能发生的世界也是有趣的。

8

XML节点顺序很重要的一个原因是,当应用程序使用流式解析器时。将依赖元素按照预期顺序排列可以使应用程序在处理XML数据时更加高效。对于处理大规模XML数据的应用程序来说尤其如此。


3
答案在于XML-DTD/Schema。API中定义的底层架构导致错误。虽然我不想在这里教授XML知识,但是查看以下内容会使事情更加清晰。
XML有两个要考虑的点:
- Well Formed XML:完美的语法 - Valid XML:与DTD(文档类型定义)/架构完全有效
关于DTD的一些要点: 建议在您的问题上使用DTD:
<!DOCTYPE transaction
[
<!ELEMENT address (#PCDATA)>
<!ELEMENT amount (#PCDATA)>
<!ELEMENT orderid (#PCDATA)>
]>

以上是在您提供的结构基础上建议的DTD。由于您正在处理特定的API,因此它已经定义了这种类型的结构。另一种选择是XML模式

关于XML模式的要点:

<xs:element name="transaction">    
<xs:complexType>
  <xs:sequence>
    <xs:element name="address" type="xs:string"/>
    <xs:element name="amount" type="xs:string"/>
    <xs:element name="orderid" type="xs:string"/>
  </xs:sequence>
</xs:complexType>
</xs:element>

目前,XML schema被用来定义数据结构,而不是DTD,因为它们对于用户来说更加优越,并提供了面向对象的方法


+1 能否举个例子说明如何修改DTD和模式以使addressamountorderid可以按任意顺序有效?这是否会导致更复杂的DTD/模式?如果是的话,这可能是开发人员强制执行顺序的一个原因... - El Ronnoco
排序的答案在于这些文件是从标签到标签解析的。解析文件的相关应用程序将按照模式中提供的顺序解析文件。如果您构建自定义解析器库,肯定可以更改顺序...只是为了使解析逻辑更加复杂! - jagbandhuster

2

依赖元素的顺序,可以让代码更快、更简单。

此外,当元素的顺序允许是任意的时候,这种方式还可以避免某些不明确的问题。

另外,XML 并不像面向人类读者,而是为计算机程序消耗而设计的。计算机喜欢按顺序执行。


1
但是我的问题在于,开发者/库要验证元素的正确顺序,这不会需要更多的努力吗? - helloandre
验证可能需要更多的工作,但是假设顺序则需要更少的工作。 - John Saunders

1

强制执行的顺序可以让消费者更加简单,例如:

consumeTransation:
    consumeAddressIfPresent;
    consumeAmountIfPresent;
    consumeOrderIDIfPresent;

更重要的是,使用XML Schema进行结构定义,使得顺序更可能成为一个要求。这是因为XML Schema对有序列表(xs:sequence)有更丰富的支持,而不是无序列表(xs:all)。后者具有出现次数限制,更难验证,并且在可扩展性方面不如序列。 在XML Schema 1.1中改进了其中的一些问题,但大多数工具/ API还没有到那个地步。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接