Convert the following Linq to xml to .net 2.0 - c#

I am recently working on a .net 2.0 project I have to read some xml files and replace certain elements value.
Wondering how you do it the following not using linq to xml?
IEnumerable<XElement> cities= xmldoc.Descendants("City")
.Where(x => x.Value == "London");
foreach (XElement myElem in cities)
{
myElem.ReplaceWith(new XElement("City", "NewCity"));
}
or
var xElement = xdoc.Descendants("FirstName").Where(x => x.Value == "Max").First();
xElement.ReplaceWith(new XElement("FirstName", "NewValue");
Any suggestions

You can consider using XmlDocument, like this:
string xmlFile = "<xml><data<test /><test /><test /><test /></data></xml>";
var xmlDoc = new XmlDocument();
xmlDoc.Load(xmlFile);
var oNodes = xmlDoc.SelectNodes("//test");
foreach (var oNode in oNodes)
{
oNode.InnerText = "bla bla";
}
xmlDoc.Save("..path to xml file");
(In your case you can use InnerXml property of the document)
http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.aspx
To selectNodes you should pass XPath Query, reference can be found:
http://www.w3schools.com/xpath/
Also if you XML contains namespace, you need to use XmlNamespaceManager:
http://msdn.microsoft.com/en-us/library/system.xml.xmlnamespacemanager.aspx
Otherwise xpath won't work.

You will need to use XmlDocument and query it using XPath with SelectNodes.
It will not be as nice and succint.

Related

C# split xml innertext or parse innerxml

I have an XML file with a structure similar to this
<entry name="something">
<members>
<member>aaa</member>
<member>bbb</member>
</members>
</entry>
<entry name="something_else">
<members>
<member>ccc</member>
<member>ddd</member>
</members>
</entry>
I need to be able to get the values out of each of the member nodes to store in a datatable. if i use the innertext property, it concatenates the values (aaabbb). there is nothing discernible to split the string on. I can also use the inner XML but then i just get a string with the XML structure (aaa bbb<\member>)
What is the best way to get each value out of the XML elements and store it in a string array?
here is what I have been trying.
foreach (XmlNode grpNode in GrpList)
{
subNode = grpNode.Attributes["name"];
if (subNode != null)
{
Obj = grpNode.Attributes["name"].Value;
}
subNode = grpNode["members"];
if (subNode != null)
{
string innerXml = string.Empty;
innerXml = grpNode["members"].InnerXml.ToString();
string[] tempArrary = innerXml.Split(new char[] {'>', '<'});
}
}
You can use Xpath to iterate through Entry nodes and get the members within it like this
string xml = "<root><entry name='something'>" +
"<members>" +
"<member>aaa</member>" +
"<member>bbb</member>" +
"</members>" +
"</entry>" +
"<entry name='something_else'>" +
"<members>" +
"<member>ccc</member>" +
"<member>ddd</member>" +
"</members>" +
"</entry></root>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var memsList = doc.SelectNodes("//entry");
foreach (XmlNode a in memsList)
{
Console.WriteLine(a.Attributes["name"].Value);
var memList = a.SelectNodes("members/member");
foreach(XmlNode x in memList)
Console.WriteLine(x.InnerText);
}
You need to iterate the child elements within members, so something like:
foreach (var node in grpNode["members"].ChildNodes)
{
var value = node.InnerText;
}
That said, you would be better off using LINQ to XML unless you have some specific reason to use XmlDocument. This gives you much more expressive code, for example:
var doc = XDocument.Parse(xml);
var something = doc.Descendants("entry")
.Where(e => (string)e.Attribute("name") == "something")
.Single();
var somethingMembers = something.Descendants("member")
.Select(e => e.Value)
.ToArray();
This should do the trick:
XDocument xdoc = XDocument.Load(#"Path/to/file");
var result = xdoc.Descendants("member").Select (x => x.Value).ToArray();
Result:
Demo Code
the xml you've provided isn't valid. But assuming you just want the inner text of all member nodes into a string array, I'd just use Linq-To-Xml (XDocument):
var results = XDocument.Parse(xmlString)
.Descendants("member")
.Select(m => m.Value)
.ToArray();
Even though you're using the old XmlDocument API, by throwing in an .OfType<XmlNode>() you can convert an XmlNodeList to a generic enumerable and thereby mix in some linq and lambda syntax, for instance:
var tempArrary = subNode.SelectNodes("member").OfType<XmlNode>().Select(n => n.InnerText).ToArray();

Inserting and removing nodes from an XML namespace

I'm trying to replace a node's name but I'm getting the following error "The reference node is not a child of this node". I think I know why this is happening but can't seem to work around this problem. Here is the XML:
<payload:Query1 xmlns="" xmlns:payload="" xmlns:xsi="" xsi:schemaLocation="">
<payload:QueryId>stuff</payload:QueryId>
<payload:Data>more stuff</payload:Data>
</payload:Query1>
And here is the C# bit:
doc.Load(readStream);
nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("payload", "location");
XmlNode Query1 = doc.SelectSingleNode("//payload:Query1", nsmgr);
public XmlDocument sendReply(args)
{
XmlNode newNode = doc.CreateElement("payload:EditedQuery");
Query.InsertBefore(newNode, Query1);
Query.RemoveChild(Query1);
return doc;
}
I'm trying to replace "Query" with "EditedQuery" but his doesn't work.
If you can use .Net 3.5 LINQ to XML,
XElement root = XElement.Load(readStream);
XNamespace ns = "http://somewhere.com";
XElement Query1 = root.Descendants(ns + "Query1").FirstOrDefault();
// should check for null first on Query1...
Query1.ReplaceWith(new XElement(ns + "EditedQuery"));
Or, if you don't know the namespace, or don't want to hard-code it:
XElement root = XElement.Load(readStream);
XElement Query1 = root.Descendants()
.FirstOrDefault(x => x.Name.Localname == "Query1");
// should check for null first on Query1...
Query1.ReplaceWith(new XElement(Query1.Name.Namespace + "EditedQuery"));
See Jon Skeet's reason why to use LINQ to XML here over older API's.

Setting values to loaded xml

How can I write specific values to my loaded xml? For instance, I want the value of OriginSource to change for PreferenceID 3. What's the most efficient way to do that?
This is a short sample of what I'm trying to do.
XmlDocument doc = new XmlDocument();
XmlElement el = (XmlElement)doc.AppendChild(doc.CreateElement("UserObject"));
XmlNode emailAddressXml = UserEmailAddressDTO.AppendChild(doc.CreateNode(XmlNodeType.Element, "EmailAddress", null));
emailAddressXml.InnerText = emailaddress;
doc.Load("Prefs.xml");
XmlNode SourceXml = UserEmailAddressDTO.AppendChild(doc.CreateNode(XmlNodeType.Element, "Source", null));
originSourceXml.InnerXml = "Good Sam";
string usrObj = doc.outerXml;
Efficiency is subjective so I will provide my recommendation. Depending on .Net version (3.5+ I believe) you should employ Linq2Xml.
XDocument, XElement, and XAttribute are very easy to work with.
var doc = XDocument.Load("Prefs.xml");
var prefs = doc.Root.Descendents("UserEmailAddressPreferences");
Now you can iterate each XElement within the prefs using Linq. Retrieving and editing values is easy enough:
// untested code
XElement el = prefs.Elements().Where(e => e.Element("PreferenceID").Value == 3)
.Select(e => e.Element("OriginSource")
.FirstOrDefault();
el.Value = "Something else":

Using linq to xml with Htmlagilitypack

I am using HtmlAgilityPack for creatin a htmldocument from the string, like:
HtmlDocument updoc = new HtmlDocument();
updoc.load(stringContents);
Now i want to insert the HtmlNodes as a child of XElement. I tried :
XDocument xdoc = XDocument.load(path);
XElement body = xdoc.Descendants(ns + "body").Single();
body.Add(updoc.GetElementbyId("h"));
body.Add(updoc.GetElementbyId("m"));
body.Add(updoc.GetElementbyId("f"));
but result will only the object names (HtmlNodeAgilityPack, ..), not works. Basically i am trying to using the combination of HtmlAgilityPack with linq to xml. Is this possible ?
I'm just googling around for stuff, so this may not work for you. But you need to use the properties of the HtmlNode returned by GetElementbyId() to create your element.
So something like this:
HtmlNode node = updoc.GetElementbyId("h");
XElement e;
body.Add(e = new XElement(node.Name, XElement.Parse(node.InnerHtml)));
If the node has HtmlAttribute(s), add them like:
foreach(HtmlAttribute att in node.Attributes)
{
e.Add(new XAttribute(att.Name, att.Value));
}
Why not just use a StringBuilder to generate your xml and parse it with XDocument.Parse(string)
Example :
StringBuilder xmlBuilder = new StringBuilder();
//Build xml with the builder
XDocument xDoc = XDocument.Parse(xmlBuilder.ToString());

Getting a value of a key from an XML file in C#

I have an XML file with the following structure:
<Definitions>
<Definition Execution="Firstkey" Name="Somevalue"></Definition>
<Definition Execution="Secondkey" Name="Someothervalue"></Definition>
</Definitions>
How can I get the values of the keys (Firstkey, Secondkey) and write them down using C# in my .NET application?
Thanks.
Using Linq to XML this is straightforward.
To just get the keys:
var keys = doc.Descendants("Definition")
.Select(x => x.Attribute("Execution").Value);
foreach (string key in keys)
{
Console.WriteLine("Key = {0}", key);
}
To get all values:
XDocument doc = XDocument.Load("test.xml");
var definitions = doc.Descendants("Definition")
.Select(x => new { Execution = x.Attribute("Execution").Value,
Name = x.Attribute("Name").Value });
foreach (var def in definitions)
{
Console.WriteLine("Execution = {0}, Value = {1}", def.Execution, def.Name);
}
Edit in response to comment:
I think what you really want is a dictionary, that maps from a key ("Execution") to a value ("Name"):
XDocument doc = XDocument.Load("test.xml");
Dictionary<string, string> dict = doc.Descendants("Definition")
.ToDictionary(x => x.Attribute("Execution").Value,
x => x.Attribute("Name").Value);
string firstKeyValue = dict["Firstkey"]; //Somevalue
using System.Xml.Linq;
var keys = XDocument.Load("path to the XML file")
.Root
.Elements()
.Select(x => x.Attribute("Execution"));
Using XMLDocumnet/XMLNode(s):
//Load the XML document into memory
XmlDocument doc = new XmlDocument();
doc.Load("myXML.xml");
//get a list of the Definition nodes in the document
XmlNodeList nodes = doc.GetElementsByTagName("Definition");
//loop through each node in the XML
foreach (XmlNode node in nodes)
{
//access the key attribute, since it is named Execution,
//that is what I pass as the index of the attribute to get
string key = node.Attributes["Execution"].Value;
//To select a single node, check if we have the right key
if(key == "SecondKey") //then this is the second node
{
//do stuff with it
}
}
basically you load the xml into a document variable, select the nodes you wish to view. Then iterate through them and store pertinent information.
XPath would be a great choice, I'd say.
Below is a sample XPath expression.
//Definition[#Execution='Firstkey']/#Name
As a XPath expression is a string, you can easily replace 'Firstkey' with whatever you need.
Use this with a XmlDocument.SelectSingleNode or XmlDocument.SelectNodes method
Both the above mentioned methods return an XmlNode. You can easily access the XmlNode.Value
Here are some XPath expressions
Don't forget XPath Visualizer which makes working with XPath so much easier!

Categories