Read Child nodes including text and node using XPath from XElement ? LinQ - c#

Using old way of doing via XmlDocument,
string xmlstring = "<root><profile><Name>John</Name><Age>23</Age></profile></root>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlstring);
string childNodes = xmlDoc.SelectSingleNode("root/Profile").InnerXml;
// output of childNodes would be => "<Name>John</Name><Age>23</Age>";
what is the equivalent of doing the above execution in LinQ when you have XElement variable. I see XPathSelectElement method in XElement but it doesn't return the child nodes + Child nodes text. Any Ideas?

I wouldn't use XPath at all for this. I'd use:
XDocument doc = XDocument.Parse(xmlString);
var nodes = doc.Root
.Elements("profile")
.DescendantsAndSelf();
That give the profile nodes and all their descendants. It's not really clear what you're trying to do with the results, but if you can give more details I should be able to come up with the appropriate code.

Related

Insert a string in a particular position into an other string

I am work on some innerxml of an XML document.
I have to concat several parts.
I have this:
<TRANFSERT><GOOD></GOOD></TRANSFERT>
I want to insert another part, <GOOD></GOOD>, before </TRANSFERT>.
I tried this:
int pos = xmldoc.indexOf("</GOOD>");
StringBuilder sb = new StringBuilder(xmlFinal);
sb.Append(xmlModifiee,pos,xmlModifiee.length);
xmlFinal = sb.ToString();
But it doesn't work.
How can I add a small part of XML in other XML?
You shouldn't interact with XML like with ordinary string.
Use provided System.Xml.XmlDocument or System.Xml.Linq.XDocument classes:
Ordinary XmlDocument single node selection and appending new element to it:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("YourFile.xml");
XmlNode goodNode = xmlDocument.SelectSingleNode("TRANSFERT/GOOD");
XmlNode nodeToInsert = xmlDocument.CreateElement("INSERTEDNODE");
goodNode.AppendChild(nodeToInsert);
Ordinary XmlDocument iterating by nodes to find necessary (be aware for many-childed nodes) and add new child node to it:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("YourFile.xml");
foreach (XmlNode rootNode in xmlDocument.ChildNodes)
{
if (rootNode.Name == "TRANSFERT")
{
foreach (XmlNode childNode in rootNode.ChildNodes)
{
if (childNode.Name == "GOOD")
{
XmlNode nodeToInsert = xmlDocument.CreateElement("INSERTEDNODE");
childNode.AppendChild(nodeToInsert);
}
}
}
}
Linq to XML variant:
XDocument xDoc = XDocument.Load("YourFIle.xml");
XElement rootElement = xDoc.Element("TRANSFERT");
XElement goodElement = rootElement.Element("GOOD");
goodElement.Add(new XElement("INSERTEDNODE"));
Simplified Linq to XML variant:
XDocument.Load("YourFIle.xml").Element("TRANSFERT").Element("GOOD").Add(new XElement("INSERTEDNODE"));
EDITED: answering the question, example was rewrited from changing InnerText values to Append/Add new child element to GOOD node.
StringBuilder.Append can only be used to add something to the end of the string. To add something inside the string, use StringBuilder.Insert like this:
sb.Insert(pos, xmlModifiee);

How put value in each xml node

I have generated xmldocument by this code with C#,
protected XDocument generateXML()
{
XDocument xdoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Invoices",
new XElement("Invoice",
new XElement("InvoiceNumber", "s10838652")
.......
return xdoc;
}
and in another method I have:
public override void RunWintrackConnector()
{
XDocument xml = generateXML();
.....
Then I would like to put data in each XML node: (instead of s10838652 I would like to assign (string.Concat(bill.invoice, bill.num);) to the InvoiceNumber node.)
I have the right part but not sure how get access to each node of xml:
xmlnode(for example InvoiceNumber) = Win2.IntegrationXML.XMLMisc.DirtyData.getStringValue(string.Concat(bill.invoice, bill.num));
xml
.Elements("Invoices")
.Elements("Invoice")
.Elements("InvoiceNumber")
.First()
.Value = string.Concat(bill.invoice, bill.num);
edit - to go over all your invoices:
foreach(var invoice in xml.Elements("Invoices").Elements("Invoice"))
{
invoice.Element("InvoiceNumber").Value = "asdf";
}
If you are familiar with XPath, this is equivalent to selecting all invoices with "Invoices/Invoice".
You can use XElement or XDocument to write the values you need.
var valueToInsert = Win2.IntegrationXML.XMLMisc.DirtyData
.getStringValue(string.Concat(bill.invoice, bill.num));
XDocument xml = generateXML();
xml.Element("Invoices")
.Elements("Invoice").First() //this First is just an example
.Element("InvoiceNumber")
.Value = valueToInsert;
Element() Returns the first found child node, and Elements() gets a list of all child nodes with that node name. Find out your pattern of how nodes are nested and you should be all set.
As a side note, you can do the above with a XDocument variable, but I prefer to keep everything as XElement for the added Linq compatibility.

How to Replace one Xml Node with another in C#

How replace XML Node from one XML document with another XML node from another XML Document.
Please help..
You can use LINQ to Xml XElement.ReplaceWith method
// select node from one doc
XDocument xdoc1 = XDocument.Load(path_to_doc1);
XElement one = xdoc1.Descendants("One").First();
// select node from another doc
XDocument xdoc2 = XDocument.Load(path_to_doc2);
XElement another = xdoc2.Descendants("Another").First();
// replace one xml node with another
one.ReplaceWith(another);
xdoc1.Save(path_to_doc1);

NodeList.SelectSingleNode() syntax

Having problems getting NodeList.SelectSingleNode() to work properly.
My XML looks like this:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<inm:Results xmlns:inm="http://www.namespace.com/1.0">
<inm:Recordset setCount="18254">
<inm:Record setEntry="0">
<!-- snip -->
<inm:Image>fileName.jpg</inm:Image>
</inm:Record>
</inm:Recordset>
</inm:Results>
The data is a long series of <inm:Record> entries.
I open the doc and get create a NodeList object based on "inm:Record". This works great.
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNodeList xRecord = xdoc.GetElementsByTagName("inm:Record");
I start looping through the NodeList using a for loop. Before I process a given entry, I want to check and see if the <inm:Image> is set. I thought it would be super easy just to do
string strImage = xRecord[i].SelectSingleNode("inm:Image").InnerText;
My thinking being, "For the XRecord that I'm on, go find the <inm:Image> value ...But this doesn't work as I get the exception saying that I need a XmlNameSpaceManager. So, I tried to set that up but could never get the syntax right.
Can someone show me how to use the correct XmlNameSpaceManager syntax in this case.
I've worked around the issue for now by looping through all of the childNodes for a given xRecord, and checking the tag once I loop around to it. I would like to check that value first to see if I need to loop over that <inm:Record> entry at all.
No need to loop through all the Record elements, just use XPath to specify the subset that you want:
XmlDocument xdoc = new XmlDocument();
xdoc.Load(openFileDialog1.FileName);
XmlNamespaceManager manager = new XmlNamespaceManager(xdoc.NameTable);
manager.AddNamespace("inm", "http://www.inmagic.com/webpublisher/query");
XmlNodeList nodes = xdoc.SelectNodes("/inm:Results/inm:Recordset/inm:Record[inm:Image != '']", manager);
Using the LINQ to XML libraries, here's an example for retrieving that said node's value:
XDocument doc = XDocument.Load(openFileDialog1.FileName);
List<XElement> docElements = doc.Elements().ToList();
XElement results = docElements.Elements().Where(
ele => ele.Name.LocalName == "Results").First();
XElement firstRecord = results.Elements().Where(
ele => ele.Name.LocalName == "Record").First();
XElement recordImage = firstRecord .Elements().Where(
ele => ele.Name.LocalName == "Image").First();
string imageName = recordImage.Value;
Also, by the way, using Hungarian notation for a type-checked language is overkill. You don't need to prepend string variables with str when it will always be a string.
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xdoc.NameTable);
string strImage = xRecord[i].SelectSingleNode("inm:Image",nsMgr).InnerText;
Should do it.
Using this Xml library, you can get all the records that have an Image child element with this:
XElement root = XElement.Load(openFileDialog1.FileName);
XElement[] records = root.XPath("//Record[Image]").ToArray();
If you want to be sure that the Image child contains a value, it can be expressed like this:
XElement[] records = root.XPath("//Record[Image != '']").ToArray();

.NET : How do you remove a specific node from an XMLDocument using XPATH?

Using C#
How do you remove a specific node from an XMLDocument using XPATH?
If you want to delete nodes, that are not direct children of the documents root, you can do this:
XmlDocument doc = new XmlDocument();
// ... fill or load the XML Document
XmlNode childNode = doc.SelectSingleNode("/rootnode/childnode/etc"); // apply your xpath here
childNode.ParentNode.RemoveChild(childNode);
Here you go. ChildNodeName, could be just the node name or an XPath query.
XmlDocument doc = new XmlDocument();
// Load you XML Document
XmlNode childNode = doc.SelectSingleNode(childNodeName);
// Remove from the document
doc.RemoveChild(childNode);
There is a different way using Linq, but I guessed you were using .NET 2.0
XPath can only select nodes from a document, not modify the document.

Categories

Resources