I see nothing wrong with the use of attributes in that sample XML. Attributes have a number of limitations that elements don't, and a couple of significant advantages.
First, the limitations:
- Attributes may only contain simple content.
- Attribute names must be unique within an element.
- By definition, the ordering of attributes is not significant in XML; you can't rely on the DOM to iterate over or save attributes in any specific order.
- Attributes aren't nodes, which means that there are some eccentricities in how you access them in XPath (e.g., the pattern
node() | @*
used in the XSLT identity transform) and in the DOM (e.g. in .NET, XmlAttribute
derives from XmlNode
even though attributes aren't nodes, and XmlAttributeCollection
doesn't derive from XmlNodeList
even though it's a list of XmlNode
objects - there are good reasons for this, but it's pretty confusing if you're new to it).
The significant advantages:
- Because attribute names must be unique within an element, and can only contain simple content, the DOM methods to set and get attribute values are significantly simpler to use than the DOM methods for setting and getting values within elements.
- Because attribute ordering is not significant, there's no need for code that creates and uses attributes to be concerned with their ordering.
- Because attributes may only contain simple content, it's easier to write schema definitions for them.
- The markup for attributes is more concise than the markup for elements.
Attributes isomorphize onto maps/dictionaries very cleanly. You can use attributes as the persistable form of any data structure consisting of name/value pairs, so long as it's OK to restrict the names to valid XML names and the values to text - and so long as when you construct the data structure it doesn't matter what order you populate it in.
(This can cause big problems. In WPF, you can use attributes in XAML to store the values of object properties that have side effects when they're set. Doing this makes for bugs that are freakishly difficult to diagnose - just because you set Binding
in your XAML before you set SelectedItem
doesn't mean that the XamlReader
is going to do that when it constructs the object that your XAML represents, and if it tries to set SelectedItem
on an object that doesn't have a Binding
yet it'll throw an exception. You can look at your XAML all day long and not see why that's happening.)
In code, the benefits of using attributes are self-evident. To set and get the value of a foo
attribute on an element using the XmlDocument
DOM (in C#):
elm.SetAttribute("foo", value);
value = elm.GetAttribute("foo");
To set and get the value of a foo
element on an element:
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 : "";
There are certainly more efficient ways to do the above (write helper methods, use XDocument
instead of XmlDocument
, or avoid the DOM completely and use serialization), but it's inherently more complex to work with elements.
In your example, it's probably OK to use attributes; it looks like they represent a simple name/value pair mapping with insignificant ordering. The exception might be the titles; if it's ever desirable to allow them to contain markup, you'll come to grief.
Edit:
Actually, I believe the XamlReader
will process attributes in the order they appear in the XAML, so if you set Binding
before SelectedItem
in your XAML it probably won't cause an exception - so long as the XamlReader
is reading from the actual text of the XAML. The risk is really that tools that read and write XML documents will alter the ordering of attributes in a XAML document. Does KaXaml preserve the order of attributes in the XAML documents it edits? It shouldn't have to.
At any rate, the solution in XAML is simple: instead of doing this:
<ListBox Binding="{...}" SelectedItem="..." ... />
do this:
<ListBox>
<ListBox.Binding>...</ListBox.Binding>
<ListBox.SelectedItem>...</ListBox.SelectedItem>
...