我认为在该示例 XML 中使用属性没有任何问题。属性有许多元素没有的限制,以及一些显着的优势。
一、局限性:
- 属性只能包含简单的内容。
- 属性名称在元素中必须是唯一的。
- 根据定义,属性的顺序在 XML 中并不重要;您不能依赖 DOM 以任何特定顺序迭代或保存属性。
- 属性不是节点,这意味着在 XPath(例如,
node() | @*
在 XSLT 身份转换中使用的模式)和在 DOM(例如,在 .NET 中,即使属性不是,也XmlAttribute
派生自XmlNode
节点,并且即使它是对象列表XmlAttributeCollection
也不是派生自它- 有很好的理由,但如果你是新手,它会很混乱)。XmlNodeList
XmlNode
显着优势:
- 因为属性名称在元素内必须是唯一的,并且只能包含简单的内容,所以设置和获取属性值的 DOM 方法比在元素内设置和获取值的 DOM 方法使用起来要简单得多。
- 因为属性排序并不重要,所以创建和使用属性的代码不需要关心它们的排序。
- 因为属性可能只包含简单的内容,所以更容易为它们编写模式定义。
- 属性标记比元素标记更简洁。
属性非常干净地同构到地图/字典上。您可以将属性用作由名称/值对组成的任何数据结构的可持久形式,只要可以将名称限制为有效的 XML 名称并将值限制为文本 - 并且只要在构造数据结构时它不会不管你以什么顺序填充它。
(这可能会导致大问题。在 WPF 中,您可以使用 XAML 中的属性来存储对象属性的值,这些属性在设置时会产生副作用。这样做会导致非常难以诊断的错误 - 只是因为您设置Binding
了您在设置之前的 XAMLSelectedItem
并不意味着XamlReader
当它构造您的 XAML 表示的对象时会这样做,并且如果它尝试SelectedItem
在一个还没有 a 的对象上设置Binding
它会引发异常。你可以整天查看您的 XAML,却看不到为什么会发生这种情况。)
在代码中,使用属性的好处是不言而喻的。要使用DOM(在 C# 中)设置和获取foo
元素上的属性值:XmlDocument
elm.SetAttribute("foo", value);
value = elm.GetAttribute("foo");
foo
要在元素上设置和获取元素的值:
XmlElement fooElm = (XmlElement)elm.SelectSingleNode("foo");
if (fooElm == null)
{
elm.OwnerDocument.CreateElement("foo");
elm.AppendChild(fooElm);
}
fooElm.InnerText = value;
XmlElement fooElm = (XmlElement)elm.SelectSingleNode("foo");
value = fooElm != null ?? fooElm.InnerText : "";
当然有更有效的方法来完成上述操作(编写辅助方法,使用XDocument
代替XmlDocument
,或完全避免 DOM 并使用序列化),但使用元素本质上更复杂。
在您的示例中,使用属性可能没问题;看起来它们代表了一个简单的名称/值对映射,顺序无关紧要。标题可能是个例外。如果允许它们包含标记是可取的,你会伤心的。
编辑:
实际上,我相信XamlReader
将按照它们在 XAML 中出现的顺序处理属性,因此如果您Binding
之前SelectedItem
在 XAML 中设置它可能不会导致异常 - 只要XamlReader
从 XAML 的实际文本中读取。真正的风险是读取和写入 XML 文档的工具会改变 XAML 文档中属性的顺序。KaXaml 是否保留其编辑的 XAML 文档中的属性顺序?它不应该。
无论如何,XAML 中的解决方案很简单:而不是这样做:
<ListBox Binding="{...}" SelectedItem="..." ... />
做这个:
<ListBox>
<ListBox.Binding>...</ListBox.Binding>
<ListBox.SelectedItem>...</ListBox.SelectedItem>
...