Reputation: 1127
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
Upvotes: 0
Views: 4221
Reputation: 32445
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";
}
}
Upvotes: 0
Reputation: 116098
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);
Upvotes: 0
Reputation: 4869
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";
}
Upvotes: 4