在工作中,我们被要求创建 XML 文件以将数据传递给另一个离线应用程序,然后该应用程序将创建第二个 XML 文件以传回以更新我们的一些数据。在此过程中,我们一直在与其他应用程序的团队讨论 XML 文件的结构。
我想出的样本基本上是这样的:
<INVENTORY>
<ITEM serialNumber="something" location="something" barcode="something">
<TYPE modelNumber="something" vendor="something"/>
</ITEM>
</INVENTORY>
另一个团队说这不是行业标准,属性只能用于元数据。他们建议:
<INVENTORY>
<ITEM>
<SERIALNUMBER>something</SERIALNUMBER>
<LOCATION>something</LOCATION>
<BARCODE>something</BARCODE>
<TYPE>
<MODELNUMBER>something</MODELNUMBER>
<VENDOR>something</VENDOR>
</TYPE>
</ITEM>
</INVENTORY>
我建议第一个的原因是创建的文件的大小要小得多。在传输过程中,文件中将有大约 80000 个项目。他们的建议实际上比我建议的要大三倍。我搜索了提到的神秘的“行业标准”,但我能找到的最接近的是 XML 属性应该只用于元数据,但说辩论是关于什么是元数据。
在冗长的解释之后(抱歉),您如何确定什么是元数据,以及在设计 XML 文档的结构时,您应该如何决定何时使用属性或元素?
我使用这个经验法则:
属性是自包含的东西,即颜色、ID、名称。元素是具有或可能具有自己的属性或包含其他元素的东西。
所以你的很接近。我会做类似的事情:
编辑:根据下面的反馈更新了原始示例。
<ITEM serialNumber="something">
<BARCODE encoding="Code39">something</BARCODE>
<LOCATION>XYX</LOCATION>
<TYPE modelNumber="something">
<VENDOR>YYZ</VENDOR>
</TYPE>
</ITEM>
属性的一些问题是:
属性不能包含多个值(子元素可以)
属性不易扩展(以备将来更改)
属性不能描述结构(子元素可以)
属性更难被程序代码操作
属性值不容易针对 DTD 进行测试
如果您将属性用作数据的容器,那么您最终会得到难以阅读和维护的文档。尝试使用元素来描述数据。仅使用属性来提供与数据无关的信息。
不要这样结束(这不是应该使用 XML 的方式):
<note day="12" month="11" year="2002"
to="Tove" to2="John" from="Jani" heading="Reminder"
body="Don't forget me this weekend!">
</note>
来源:http://www.w3schools.com/xml/xml_dtd_el_vs_attr.asp
list
是解决此问题的部分解决方法。不能有多个同名的属性。 list
属性仍然只有一个值,它是一些数据类型的空格分隔列表。分隔字符是固定的,因此如果所需数据类型的单个值可以包含空格,则不能有多个值。这排除了在一个“地址”属性中具有例如多个地址的可能性。
“XML”代表“可扩展标记语言”。标记语言意味着数据是文本,用有关结构或格式的元数据进行标记。
XHTML 是一个按照预期方式使用 XML 的示例:
<p><span lang="es">El Jefe</span> insists that you
<em class="urgent">MUST</em> complete your project by Friday.</p>
在这里,元素和属性之间的区别很明显。文本元素显示在浏览器中,属性是关于如何显示它们的说明(尽管有一些标签不能这样工作)。
当 XML 不是用作标记语言,而是用作数据序列化语言时,就会出现混淆,其中“数据”和“元数据”之间的区别更加模糊。所以元素和属性之间的选择或多或少是任意的,除了不能用属性表示的东西(见芬斯特的回答)。
XML 元素与 XML 属性
XML 是关于协议的。首先遵循您的社区或行业内的任何现有 XML 模式或已建立的约定。
如果您确实需要从头开始定义您的模式,那么这里有一些一般性的考虑因素应该通知元素与属性的决定:
<versus>
<element attribute="Meta content">
Content
</element>
<element attribute="Flat">
<parent>
<child>Hierarchical</child>
</parent>
</element>
<element attribute="Unordered">
<ol>
<li>Has</li>
<li>order</li>
</ol>
</element>
<element attribute="Must copy to reuse">
Can reference to re-use
</element>
<element attribute="For software">
For humans
</element>
<element attribute="Extreme use leads to micro-parsing">
Extreme use leads to document bloat
</element>
<element attribute="Unique names">
Unique or non-unique names
</element>
<element attribute="SAX parse: read first">
SAX parse: read later
</element>
<element attribute="DTD: default value">
DTD: no default value
</element>
</versus>
这可能取决于您的使用情况。用于表示从数据库生成的结构化数据的 XML 可以很好地与最终作为属性放置的字段值一起工作。
然而,用作消息传输的 XML 通常使用更多元素会更好。
例如,假设我们在答案中提出了这个 XML:-
<INVENTORY>
<ITEM serialNumber="something" barcode="something">
<Location>XYX</LOCATION>
<TYPE modelNumber="something">
<VENDOR>YYZ</VENDOR>
</TYPE>
</ITEM>
</INVENTORY>
现在我们想将 ITEM 元素发送到设备以打印条形码,但是可以选择编码类型。我们如何表示所需的编码类型?突然间,我们意识到,有点晚了,条形码不是一个单一的自动值,而是它可能符合打印时所需的编码。
<ITEM serialNumber="something">
<barcode encoding="Code39">something</barcode>
<Location>XYX</LOCATION>
<TYPE modelNumber="something">
<VENDOR>YYZ</VENDOR>
</TYPE>
</ITEM>
关键是,除非您构建某种 XSD 或 DTD 以及命名空间来固定结构,否则最好保留您的选项。
IMO XML 在不破坏现有代码的情况下可以灵活使用时最有用。
关于属性与元素,我在架构设计中使用以下准则:
对长时间运行的文本使用元素(通常是字符串或规范化字符串类型的元素)
如果一个元素有两个值(例如 eventStartDate 和 eventEndDate)的分组,则不要使用属性。在前面的示例中,“event”应该有一个新元素,其中可能包含 startDate 和 endDate 属性。
业务日期、日期时间和数字(例如计数、金额和比率)应该是元素。
非业务时间元素,如 last updated、expires on 应该是属性。
哈希码和索引等非业务数字应该是属性。* 如果类型很复杂,请使用元素。
如果值是简单类型且不重复,则使用属性。
xml:id 和 xml:lang 必须是引用 XML 模式的属性
在技术上可能的情况下首选属性。
属性的偏好是它提供以下内容:
唯一(属性不能出现多次)
顺序无所谓
上述属性是可继承的(这是“所有”内容模型在当前模式语言中不支持的东西)
好处是它们不那么冗长并且占用的带宽更少,但这并不是更喜欢属性而不是元素的真正理由。
我在技术上可行时添加,因为有时无法使用属性。例如,属性集选择。例如使用 (startDate and endDate) xor (startTS and endTS) 在当前模式语言中是不可能的
如果 XML Schema 开始允许限制或扩展“所有”内容模型,那么我可能会放弃它
这个问题没有统一的答案(我大量参与了 W3C 规范的创建)。 XML 可用于多种用途——文本类文档、数据和声明性代码是最常见的三种。我也经常使用它作为数据模型。这些应用程序的某些方面属性更常见,而其他方面则子元素更自然。各种工具还具有使使用它们变得更容易或更难的功能。
XHTML 是属性具有自然用途的一个领域(例如,在 class='foo' 中)。属性没有顺序,这可能使某些人更容易开发工具。 OTOH 属性在没有模式的情况下更难键入。我还发现命名空间属性 (foo:bar="zork") 在各种工具集中通常更难管理。但是请查看一些 W3C 语言以了解常见的混合。 SVG、XSLT、XSD、MathML 是一些知名语言的例子,它们都有丰富的属性和元素。有些语言甚至允许不止一种方式来做到这一点,例如
<foo title="bar"/>;
或者
<foo>
<title>bar</title>;
</foo>;
请注意,这些在语法上并不等效,并且需要处理工具中的明确支持)
我的建议是查看最接近您的应用程序的领域的常见做法,并考虑您可能希望应用哪些工具集。
最后确保区分命名空间和属性。一些 XML 系统(例如 Linq)将名称空间表示为 API 中的属性。 IMO 这很丑陋并且可能令人困惑。
其他人已经涵盖了如何区分属性和元素,但从更一般的角度来看,将所有内容都放在属性中,因为它会使生成的 XML 更小是错误的。
XML 的设计目的不是为了紧凑,而是为了便于携带和可读。如果您想减少传输中数据的大小,请使用其他内容(例如 google's protocol buffers)。
百万美元的问题!
首先,现在不要太担心性能。您会惊讶于优化的 xml 解析器会以多快的速度破解您的 xml。更重要的是,您对未来的设计是什么:随着 XML 的发展,您将如何保持松散耦合和互操作性?
更具体地说,您可以使元素的内容模型更复杂,但更难扩展属性。
这两种存储对象属性的方法都是完全有效的。你应该脱离务实的考虑。尝试回答以下问题:
哪种表示导致更快的数据解析\生成?哪种表示会导致更快的数据传输?可读性重要吗? ...
对数据使用元素,对元数据使用属性(关于元素数据的数据)。
如果一个元素在您的选择字符串中显示为谓词,那么您有一个很好的迹象表明它应该是一个属性。同样,如果一个属性从不用作谓词,那么它可能不是有用的元数据。
请记住,XML 应该是机器可读的而不是人类可读的,并且对于大型文档,XML 压缩得非常好。
无论哪种方式都有争议,但您的同事在某种意义上是正确的,即 XML 应该用于“标记”或围绕实际数据的元数据。就您而言,您是对的,在用 XML 对您的域进行建模时,有时很难确定元数据和数据之间的界限在哪里。实际上,我所做的是假装标记中的任何内容都是隐藏的,只有标记之外的数据是可读的。以这种方式,该文件是否有意义?
XML 是出了名的笨重。对于传输和存储,如果您负担得起处理能力,强烈建议进行压缩。 XML 压缩得很好,有时甚至非常好,因为它具有重复性。我已经将大文件压缩到其原始大小的 5% 以下。
支持您立场的另一点是,当另一个团队在争论样式时(因为大多数 XML 工具将像处理全#PCDATA 文档一样容易地处理全属性文档),您正在争论实用性。虽然不能完全忽视风格,但技术优势应该更重要。
这在很大程度上是一个偏好问题。我尽可能使用元素进行分组和数据属性,因为我认为这比替代方案更紧凑。
比如我更喜欢......
<?xml version="1.0" encoding="utf-8"?>
<data>
<people>
<person name="Rory" surname="Becker" age="30" />
<person name="Travis" surname="Illig" age="32" />
<person name="Scott" surname="Hanselman" age="34" />
</people>
</data>
...代替....
<?xml version="1.0" encoding="utf-8"?>
<data>
<people>
<person>
<name>Rory</name>
<surname>Becker</surname>
<age>30</age>
</person>
<person>
<name>Travis</name>
<surname>Illig</surname>
<age>32</age>
</person>
<person>
<name>Scott</name>
<surname>Hanselman</surname>
<age>34</age>
</person>
</people>
</data>
但是,如果我的数据在 20-30 个字符内不容易表示或包含许多引号或其他需要转义的字符,那么我会说是时候分解元素了……可能使用 CData 块。
<?xml version="1.0" encoding="utf-8"?>
<data>
<people>
<person name="Rory" surname="Becker" age="30" >
<comment>A programmer whose interested in all sorts of misc stuff. His Blog can be found at http://rorybecker.blogspot.com and he's on twitter as @RoryBecker</comment>
</person>
<person name="Travis" surname="Illig" age="32" >
<comment>A cool guy for who has helped me out with all sorts of SVn information</comment>
</person>
<person name="Scott" surname="Hanselman" age="34" >
<comment>Scott works for MS and has a great podcast available at http://www.hanselminutes.com </comment>
</person>
</people>
</data>
如何利用我们来之不易的面向对象直觉?我通常会直接想到哪个是对象,哪个是对象的属性,或者它指的是哪个对象。
任何直观上有意义的对象都应该作为元素。它的属性(或属性)将是 xml 中这些元素的属性或具有属性的子元素。
我认为对于示例中的面向对象类比等更简单的情况,可以确定哪个是元素,哪个是元素的属性。
只是对一些不良信息的一些更正:
@John Ballinger:属性可以包含任何字符数据。 < > & " ' 需要分别转义为 < > & " 和 ' 。如果您使用 XML 库,它会为您解决这个问题。
地狱,一个属性可以包含二进制数据,如图像,如果你真的想要,只需通过 base64 编码并将其设为 data: URL。
@feenster:在IDS或NAMES的情况下,属性可以包含以空格分隔的多个项目,其中包括数字。挑剔,但这最终可以节省空间。
使用属性可以保持 XML 与 JSON 的竞争力。请参阅 Fat Markup: Trimming the Fat Markup Myth one calorie at a time。
我总是对这类讨论的结果感到惊讶。对我来说,有一个非常简单的规则来决定数据是属于属性还是属于内容,那就是数据是否具有可导航的子结构。
例如,非标记文本总是属于属性。总是。
列表属于子结构或内容。可能随着时间的推移包含嵌入的结构化子内容的文本属于内容。 (根据我的经验,在使用 XML 进行数据存储或交换时,这种情况相对较少——带有标记的文本。)
以这种方式编写的 XML 模式非常简洁。
每当我看到像 <car><make>Ford</make><color>Red</color></car>
这样的情况时,我都会想“哎呀,作者认为 make 元素中会有子元素吗?” <car make="Ford" color="Red" />
更具可读性,毫无疑问如何处理空格等。
仅给出空白处理规则,我相信这是 XML 设计者的明确意图。
<color roof="black" doors="red"/>
这在 HTML 中非常清楚,可以清楚地看到属性和标记的差异:
所有数据都在标记之间 属性用于表征该数据(例如格式)
如果您只是将纯数据作为 XML,则存在不太明显的区别。数据可以位于标记之间或作为属性。
=> 大多数数据应该位于标记之间。
如果您想在这里使用属性:您可以将数据分为两类:数据和“元数据”,其中元数据不是您要呈现的记录的一部分,而是诸如“格式版本”、“创建日期”之类的内容, ETC。
<customer format="">
<name></name>
...
</customer>
也可以说:“使用属性来表征标签,使用标签来提供数据本身。”
我同意芬斯特的观点。如果可以,请远离属性。元素是进化友好的,并且在 Web 服务工具包之间更具互操作性。您永远不会发现这些工具包使用属性序列化您的请求/响应消息。这也是有道理的,因为我们的消息是 Web 服务工具包的数据(不是元数据)。
相信我,随着时间的推移,属性很容易变得难以管理。我个人总是远离他们。解析器和用户都更加明确和可读/可用的元素。
我唯一一次使用它们是定义资产 url 的文件扩展名:
<image type="gif">wank.jpg</image> ...etc etc
我想如果你知道 100% 不需要扩展属性,你可以使用它们,但你知道多少次。
<image>
<url>wank.jpg</url>
<fileType>gif</fileType>
</image>
<
的替换文本是<
,它是字符引用,而不是实体引用。<
在属性上是可以的。请参阅:w3.org/TR/REC-xml/#sec-predefined-ent]]>
!)