Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

select all xml nodes which contain a certain attribute

Tags:

c#

xml

xpath

I have to select all nodes which contain an attribute with a certain name.

This is my current, not working approach.

public List<string> RetrieveValuesForAttribute(string attributeName)
{
    var list = new List<string>();

    string xpath = "//*[@Name='" + attributeName + "']";
    XmlNodeList xmlNodeList = document.SelectNodes(xpath);

    foreach (XmlNode xmlNode in xmlNodeList)
    {
        list.Add(xmlNode.Attributes[attributeName].InnerText);
    }

    return list;
} 

I try to select all nodes which contain the attribute with the name given in the method parameter attributeName and add the value the variable list.

Example:

This method call:

List<string> result = RetrieveValuesForAttribute("itemSelectedHandler");

Should return an list which contains the string "OnSelectedRelatedContactChanged"

This is the xml file:

<GroupBoxWrapper id="gbRelatedContacts" text="Related Contacts">
  <TabIndex>0</TabIndex>
  <TabStop>false</TabStop>
  <PanelWrapper id="pnlRelatedContactsView" width="1350">
    <TabIndex>0</TabIndex>
    <TabStop>false</TabStop>
    <ListViewWrapper id="lvRelatedContacts" itemSelectedHandler="OnSelectedRelatedContactChanged" itemDoubleClickHandler="OnRelatedContactDoubleClick">
      <TabIndex>0</TabIndex>
      <TabStop>true</TabStop>
      <ListViewColumns>
        <Column title="Name" mapNode="Contact\Name" />
        <Column title="Lastname" mapNode="Contact\Lastname" />
      </ListViewColumns>
    </ListViewWrapper>
  </PanelWrapper>
</GroupBoxWrapper>

Further questions: Would it be better to solve this with LINQ?

Solution 1: thank you, ywm

public List<string> RetrieveValuesForAttribute(string attributeName)
{
    var list = new List<string>();

    string xpath = @"//*[@" + attributeName + "]";
    XmlNodeList xmlNodeList = document.SelectNodes(xpath);

    foreach (XmlNode xmlNode in xmlNodeList)
    {
        list.Add(xmlNode.Attributes[attributeName].InnerText);
    }

    return list;
}

Solution 2: thank you, Jon Skeet

public List<string> RetrieveValuesForAttribute(string attributeName)
{
    //document is an XDocument
    return document.Descendants()
                   .Attributes(attributeName)
                   .Select(x => x.Value)
                   .ToList();
}

The LINQ to XML Solution looks far more elegant to me.

like image 697
Joel Avatar asked Apr 11 '13 09:04

Joel


3 Answers

If you could use LINQ to XML for this, it would be utterly trivial:

// Note that there's an implicit conversion from string to XName,
// but this would let you specify a namespaced version if you want.
public List<string> RetrieveValuesForAttribute(XName attributeName)
{
    // Assume document is an XDocument
    return document.Descendants()
                   .Attributes(attributeName)
                   .Select(x => x.Value)
                   .ToList();
} 
like image 102
Jon Skeet Avatar answered Nov 15 '22 23:11

Jon Skeet


The XPath you are looking for should be

"//*[@" + attributeName + "]"

What your original XPath was doing was looking for all elements that have a Name attribute with the value attributeName

This will look for any element which has an attribute with attributeName

//*[@title]

would return the column elements

like image 34
ywm Avatar answered Nov 15 '22 23:11

ywm


Im not sure about the C# syntax but I think the xpath vlaue is wrong. Please try: "//*[@itemSelectedHandler]". What should in c#

  string xpath = "//*[@" + attributeName + "]";
like image 28
hr_117 Avatar answered Nov 15 '22 23:11

hr_117