39

Part of the XML content:

<section name="Header">
  <placeholder name="HeaderPane"></placeholder>
</section>

<section name="Middle" split="20">
  <placeholder name="ContentLeft" ></placeholder>
  <placeholder name="ContentMiddle"></placeholder>
  <placeholder name="ContentRight"></placeholder>
</section>

<section name="Bottom">
  <placeholder name="BottomPane"></placeholder>
</section>

I want to check in each node and if attribute split exist, try to assign an attribute value in a variable.

Inside a loop, I try:

foreach (XmlNode xNode in nodeListName)
{
    if(xNode.ParentNode.Attributes["split"].Value != "")
    {
        parentSplit = xNode.ParentNode.Attributes["split"].Value;
    }
}

But I'm wrong if the condition checks only the value, not the existence of attributes. How should I check for the existence of attributes?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
4b0
  • 21,981
  • 30
  • 95
  • 142
  • While this might not have been true at the time this question was asked, nowadays there's an [XmlElement.HasAttribute Method](https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlelement.hasattribute?view=net-5.0) that, to me, seems well suited for such use cases. Just in case someone stumbles upon this... – loptrinho Jul 28 '21 at 10:59

8 Answers8

54

You can actually index directly into the Attributes collection (if you are using C# not VB):

foreach (XmlNode xNode in nodeListName)
{
  XmlNode parent = xNode.ParentNode;
  if (parent.Attributes != null
     && parent.Attributes["split"] != null)
  {
     parentSplit = parent.Attributes["split"].Value;
  }
}
Paul
  • 4,009
  • 1
  • 17
  • 15
13

If your code is dealing with XmlElements objects (rather than XmlNodes) then there is the method XmlElement.HasAttribute(string name).

So if you are only looking for attributes on elements (which it looks like from the OP) then it may be more robust to cast as an element, check for null, and then use the HasAttribute method.

foreach (XmlNode xNode in nodeListName)
{
  XmlElement xParentEle = xNode.ParentNode as XmlElement;
  if((xParentEle != null) && xParentEle.HasAttribute("split"))
  {
     parentSplit = xParentEle.Attributes["split"].Value;
  }
}
Ben
  • 3,241
  • 4
  • 35
  • 49
10

Just for the newcomers: the recent versions of C# allows the use of ? operator to check nulls assignments

parentSplit = xNode.ParentNode.Attributes["split"]?.Value;
7

You can use LINQ to XML,

XDocument doc = XDocument.Load(file);

var result = (from ele in doc.Descendants("section")
              select ele).ToList();

foreach (var t in result)
{
    if (t.Attributes("split").Count() != 0)
    {
        // Exist
    }

    // Suggestion from @UrbanEsc
    if(t.Attributes("split").Any())
    {

    }
}

OR

 XDocument doc = XDocument.Load(file);

 var result = (from ele in doc.Descendants("section").Attributes("split")
               select ele).ToList();

 foreach (var t in result)
 {
     // Response.Write("<br/>" +  t.Value);
 }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
KV Prajapati
  • 93,659
  • 19
  • 148
  • 186
  • 1
    +1 for Linq to XML. Instead of Count() != 0 you could use Any() –  Aug 25 '11 at 08:13
  • @UrbanEsc - just out of curiousity, is there anything gained by using Any() rather than Count()? – Tim Aug 25 '11 at 08:24
  • Check this SO topic http://stackoverflow.com/questions/305092/which-method-performs-better-any-vs-count-0 –  Aug 25 '11 at 08:36
5
var splitEle = xn.Attributes["split"];

if (splitEle !=null){
    return splitEle .Value;
}
user3423251
  • 51
  • 1
  • 1
3

EDIT

Disregard - you can't use ItemOf (that's what I get for typing before I test). I'd strikethrough the text if I could figure out how...or maybe I'll simply delete the answer, since it was ultimately wrong and useless.

END EDIT

You can use the ItemOf(string) property in the XmlAttributesCollection to see if the attribute exists. It returns null if it's not found.

foreach (XmlNode xNode in nodeListName)
{
    if (xNode.ParentNode.Attributes.ItemOf["split"] != null)
    {
         parentSplit = xNode.ParentNode.Attributes["split"].Value;
    }
}

XmlAttributeCollection.ItemOf Property (String)

Tim
  • 28,212
  • 8
  • 63
  • 76
  • i mean check attributes `split` exist. if attributes exist assign attribute value in variable.Thanks. – 4b0 Aug 25 '11 at 08:00
  • 1
    @Shree - the code above will check to see if the attribute "split" exists, if it does, if will assign the value of the attribute to `parentSplit`. Note that if you have more than one XmlNode in nodeListName that has a ParentNode with a "split" attribute, the last one in the list will be assigned to parentSplit, overwriting previous ones (if any). – Tim Aug 25 '11 at 08:05
  • ItemOf actually refers to a direct index into the Attribute collection. – Paul Aug 25 '11 at 08:08
  • ItemOf is the VB way of interacting with this. Indexing directly into the collection is the C# method. – Paul Aug 25 '11 at 08:16
1

Another way to handle the situation is exception handling.

Every time a non-existent value is called, your code will recover from the exception and just continue with the loop. In the catch-block you can handle the error the same way you write it down in your else-statement when the expression (... != null) returns false. Of course throwing and handling exceptions is a relatively costly operation which might not be ideal depending on the performance requirements.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
rbaleksandar
  • 8,713
  • 7
  • 76
  • 161
1

You can use the GetNamedItem method to check and see if the attribute is available. If null is returned, then it isn't available. Here is your code with that check in place:

foreach (XmlNode xNode in nodeListName)
{
    if(xNode.ParentNode.Attributes.GetNamedItem("split") != null )
    {
        if(xNode.ParentNode.Attributes["split"].Value != "")
        {
            parentSplit = xNode.ParentNode.Attributes["split"].Value;
        }
    }  
}
Rich
  • 11
  • 1
  • As others here have mentioned, it always good to check if xNode.ParentNode.Attributes is null before continuing. – Rich Feb 23 '18 at 16:26