0

I have a collection of custom objectswhich has storeid. I also have an XmlDocument which I query data from the database and constructed in memory. The StoreId property in the custome object corresponds to the "Value" object in the XML.I have to loop through my custom collection and match the StoreId to the "Value" attribute in the XML and set its "Checked" attribute equal to true. As shown in the XML below, all the "Checked" attribute values are set to false at the start.

<Tree>
<Node Text="Whole ">
  <Node Text="America">
     <Node Text="NewYork">
        <Node Value="28" Checked="false " Text="NY1" />
        <Node Value="29" Checked="false " Text="NY2" />
     </Node>
     <Node Text="Houston">
        <Node Value="13 " Checked="false " Text="H1" />
        <Node Value="14 " Checked="false " Text="H2" />
        <Node Value="16 " Checked="false " Text="H3" />
        <Node Value="19 " Checked="false " Text="H4" />
        <Node Value="26 " Checked="false " Text="H5" />
     </Node>
     <Node Text="GeorgeTown">
        <Node Value="21 " Checked="false " Text="G1" />
        <Node Value="23 " Checked="false " Text="G2" />
        <Node Value="25 " Checked="false " Text="G3" />
     </Node>
  </Node>
  </Node>
  </Tree>

My code is:

public class MyObject
 {
    public string StoreId { get; set; }
    public bool HasValue { get; set; }
 }

 Code to update XML:
 XmlDocument baseDocument = ConstructXMLFromDataBase();
 XmlNodeList dataNodes = baseDocument.SelectNodes("//Tree/Node/Node/Node");

 List<MyObject> myCollections = GetMyCollection();

 foreach (var myCollection in myCollections)
 {
    foreach (XmlNode node in dataNodes)
    {
      //code to update
    }               
 }

I believe it can be done easily with Linq to XML and I am very new to Linq to XML. Moreover most of the samples available on the internet are about updating XML loaded from a disc and not constructed in memory.

Thanks

2
  • Note that your XPath query is greedy. //Tree/... searches for all Tree tags. I think you meant /Tree/... which starts at the root. Commented Dec 31, 2016 at 17:21
  • That's because the "Value" attribute is present at the third level of the Node element. Thanks Commented Dec 31, 2016 at 17:28

3 Answers 3

4

You can accomplish the update with your method by adding one more inner loop:

foreach (XmlNode checkedNode in node.ChildNodes)
{
    checkedNode.Attributes["Checked"].Value = "true";
}

If you want to use Linq, you should switch to XDocument:

var doc = XDocument.Parse(xml);     //xml is a string, can be returned from a function, 
                                    //built dynamically, etc.

var nodesToUpdate = doc.Descendants("Node")
                       .Where(n => n.Attributes("Checked").FirstOrDefault() != null);

foreach (var node in nodesToUpdate)
{
    //TODO: check update conditions, etc.

    node.Attribute("Checked").Value = "true";
}
Sign up to request clarification or add additional context in comments.

1 Comment

Hi CoolBots, thanks! Since the additional foreach loop turned out to be simpler, I have used it.
0

I find Linq2Xml + XPath easier to use

var id = "19";
var xdoc = XDocument.Load(filename);

xdoc.XPathSelectElement($"//Node[@Value='{id}']").Attribute("Checked").Value = "true";

xdoc.Save(filename);

Comments

0

If you want using LINQ to Xml you need change ConstructXMLFromDataBase method to return XDocument object.

XDocument document = ConstructXMLFromDataBase();

If you constructed xml from the string loaded from database you can use

return XDocument.Parse(validXmlString);

In case your xml is not valid document (without <?xml.. tag) then you can return XElement

return XElement.Parse(yourXmlString);

Or use "dirty" workaround and convert it to XDocument

XmlDocument xmlDocument = ConstructXMLFromDataBase();
XDocument document;
using (var nodeReader = new XmlNodeReader(xmlDocument))
{
    document = XDocument.Load(nodeReader);    
}

And then update existed nodes. This code will work in both cases, where document is XDocument or document is XElement

var storeIdCollection = GetMyCollection().Select(myObject => myObject.StoreId);
var storeIds = new HashSet<string>(storeIdCollection);

var nodes = document.Descendants.Where(node => node.Attribute("Value") != null);
foreach(var node In nodes)
{
    var storeId = node.Attribute("Value").Value;
    If (storeIds.Contains(storeId))
    {
        node.Attribute("Checked").Value = "true";
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.