tags:

views:

93

answers:

3

I'm trying to use XPath to select the items which have a facet with Location values, but currently my attempts even to just select all items fail: The system happily reports that it found 0 items, then returns (instead the nodes should be processed by a foreach loop). I'd appreciate help either making my original query or just getting XPath to work at all.

XML

<?xml version="1.0" encoding="UTF-8" ?>
<Collection Name="My Collection" SchemaVersion="1.0" xmlns="http://schemas.microsoft.com/collection/metadata/2009" xmlns:p="http://schemas.microsoft.com/livelabs/pivot/collection/2009" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
<FacetCategories>
    <FacetCategory Name="Current Address" Type="Location"/>
    <FacetCategory Name="Previous Addresses" Type="Location" />
</FacetCategories>
    <Items>
        <Item Id="1" Name="John Doe">
            <Facets>
                <Facet Name="Current Address">
                    <Location Value="101 America Rd, A Dorm Rm 000, Chapel Hill, NC 27514" />
                </Facet>
                <Facet Name="Previous Addresses">
                    <Location Value="123 Anywhere Ln, Darien, CT 06820" />
                    <Location Value="000 Foobar Rd, Cary, NC 27519" />
                </Facet>
            </Facets>
        </Item>
    </Items>
</Collection>

C#

public void countItems(string fileName)
{
    XmlDocument document = new XmlDocument();
    document.Load(fileName);
    XmlNode root = document.DocumentElement;
    XmlNodeList xnl = root.SelectNodes("//Item");
    Console.WriteLine(String.Format("Found {0} items" , xnl.Count));
}

There's more to the method than this, but since this is all that gets run I'm assuming the problem lies here. Calling root.ChildNodes accurately returns FacetCategories and Items, so I am completely at a loss.

Thanks for your help!

+6  A: 

Your root element has a namespace. You'll need to add a namespace resolver and prefix the elements in your query.

This article explains the solution. I've modified your code so that it gets 1 result.

public void countItems(string fileName)
{
    XmlDocument document = new XmlDocument();
    document.Load(fileName);
    XmlNode root = document.DocumentElement;

    // create ns manager
    XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(document.NameTable);
    xmlnsManager.AddNamespace("def", "http://schemas.microsoft.com/collection/metadata/2009");

    // use ns manager
    XmlNodeList xnl = root.SelectNodes("//def:Item", xmlnsManager);
    Response.Write(String.Format("Found {0} items" , xnl.Count));
}
harpo
A: 

Do you have a namespacing problem (note the xmlns attribute in your root node) ? Have you tried

//:Item

to get the nodes via the local-name() i.e. not namespaced.

Brian Agnew
+1  A: 

Because you have an XML namespace on your root node, there is no such thing as "Item" in your XML document, only "[namespace]:Item", so when searching for a node with XPath, you need to specify the namespace.

If you don't like that, you can use the local-name() function to match all elements whose local name (the name part other than the prefix) is the value you're looking for. It's a bit ugly syntax, but it works.

XmlNodeList xnl = root.SelectNodes("//*[local-name()='Item']");
Adam Sills