次の方法で共有


Writing Succinct Code to move XElement and XAttribute Objects from One LINQ to XML Tree to Another

There is an interesting idiom of LINQ to XML that makes it easy to write short, succinct code when creating one XML tree from another.  Many folks are not aware of this idiom, but it is a useful and convenient trick.  I documented this idiom in the LINQ to XML documentation, however, it is worthwhile to discuss in a blog post.  This post describes this idiom in detail.

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCAs you probably know, one of the overloads of the XElement constructors is a params array, so that you can pass multiple child nodes as parameters to the parent XElement constructor.  It is perfectly valid to pass null as one of those arguments, and the XElement constructor will simply ignore that argument.  For example, in the following code, the null parameter is ignored:

XElement xmlTree = new XElement("Root",
new XElement("Child", 1),
null,
new XElement("Child", 2)
);
Console.WriteLine(xmlTree);

This example produces the following output:

<Root>
<Child>1</Child>
<Child>2</Child>
</Root>

The same semantics apply when you pass a collection of XElement objects to the constructor.  If one of the items in the collection is null, then the null item is simply ignored.

List<XElement> elementList = new List<XElement>{
new XElement("Child", 1),
null,
new XElement("Child", 3)
};
XElement xmlTree = new XElement("Root", elementList);
Console.WriteLine(xmlTree);

This example outputs:

<Root>
<Child>1</Child>
<Child>3</Child>
</Root>

And, if you use the XElement.Attribute or XElement.Element method, and pass in the name of an element or attribute that doesn’t exist, the method returns null.  Consider the following snippet:

XElement xmlTree = new XElement("Root",
new XAttribute("Att1", 1),
new XAttribute("Att3", 3)
);
if (xmlTree.Attribute("Att2") == null)
Console.WriteLine("Att2 doesn't exist");
else
Console.WriteLine("This won't be printed.");

This example will print “Att2 doesn’t exist”.

We can use these semantics to move attributes and child elements (where they may or may not exist) from one element to another.  We want to create a new Root element that contains Att2, Att3, and Att4 (but not Att1).  And we want the new Root element to contain Att2, Att3, and Att4 only if they exist in the source Root element.  We can write this code as follows:

XElement source = new XElement("Root",
new XAttribute("Att1", 1),
new XAttribute("Att3", 3),
new XAttribute("Att4", 4)
);
// move Att2, Att3, and Att4 to the new element, but only if they exist in the
// source element.
XElement newRoot = new XElement("Root",
source.Attribute("Att2"),
source.Attribute("Att3"),
source.Attribute("Att4")
);
Console.WriteLine(newRoot);

This example will produce the following output:

<Root Att3="3" Att4="4" />

As you can see in the above example, Att2 was not moved to the new tree because it didn’t exist.  And based on the above discussed semantics, LINQ to XML didn’t throw any exceptions.

The XML that the SharePoint web services return sometimes contains elements that have many attributes.  I know I'm not interested in many of these attributes when writing code to accomplish a particular task.  These uninteresting attributes obfuscate the XML, and make it harder to learn about the XML returned by the web services.  One approach that I’ve taken is to create a new ‘Report’ XML tree that contains only the elements and attributes that I’m interested in.  The idiom discussed in this post is useful when creating the ‘Report’ XML tree:

lists.GetListItems((string)l.Attribute("ID"), "", null,
viewFields.GetXmlNode(), "", queryOptions.GetXmlNode(), "")
.GetXElement()
.Descendants(z + "row")
.Select(r =>
new XElement("Row",
r.Attribute("ows_Title"),
r.Attribute("ows_ContentType"),
r.Attribute("ows_FSObjType"),
r.Attribute("ows_Attachments"),
r.Attribute("ows_FirstName"),
r.Attribute("ows_LinkFilename"),
r.Attribute("ows_EncodedAbsUrl"),
r.Attribute("ows_BaseName"),
r.Attribute("ows_FileLeafRef"),
r.Attribute("ows_FileRef"),
r.Attribute("ows_ID"),
r.Attribute("ows_UniqueId"),
r.Attribute("ows_GUID")

In this example, the code takes a number of attributes (which may or may not exist) from the “row” element, and moves them to the “Row” element in a new XML tree.

Comments

  • Anonymous
    November 23, 2009
    Hi, I have an XElement object (lets say obj), can you please tell me how can I check this for null? I want to check whether the obj is null or not? Can you suggest me please? Thanks, Sumeet