How can I navigate deeper in XML and append data in it - c#

I have loaded XmlDocument into memory and created new XmlElement. Now I am trying to add XmlElement to the path /report/section/hosts but I don't know how. I can add it easily below root node of XML but I cannot figure out how can I navigate deeper level in XML and just append there. In pseudo I am trying to do this:
doc.SelectNodes("/report/section/hosts").AppendChild(subRoot);
The code:
XmlDocument doc = new XmlDocument();
doc.Load("c:\\data.xml");
//host
XmlElement subRoot = doc.CreateElement("host");
//Name
XmlElement ElName = doc.CreateElement("name");
XmlText TxtName = doc.CreateTextNode("text text");
ElName.AppendChild(TxtName);
subRoot.AppendChild(ElName);
doc.DocumentElement.AppendChild(subRoot);
doc.Save("c:\\data.xml");

Try SelectSingleNode instead of SelectNodes
XmlElement parent = (XmlElement)doc.SelectSingleNode("/report/section/hosts")
parent.AppendChild(subRoot);

You are almost there. Try using SelectSingleNode instead:
XmlNode node = doc.SelectSingleNode("/report/section/hosts");
node.AppendChild(subRoot);

The SelectNodes method returns a list of Nodes.
You should use SelectSingleNode instead...
e.g. (top of my head, did not test in Visual Studio)
doc.SelectSingleNode("/report/section/hosts").AppendChild(subRoot);

You need to get a reference to an XmlElement in your doc (other than the root) to append to. There are a number of methods available on XmlDocument such as GetElementById and SelectSingleNode which do this for you in different ways, research to taste.
That said, the whole API in this area is generally regarded as a bit painful, do you have LINQ available?

Related

Getting an XmlNode given one of its XmlAttributes

I have an XmlNode like this:
XmlNode node = document.GetElementById("myid");
Given its attribute:
XmlAttribute a = node.Attributes("type");
Is there a way to obtain back the node?
Something like this:
XmlNode node = a.Node;
I tried ParentNode, but it doesn't seem to work (returning null).
You can use:
XmlElement node = a.OwnerElement;
or using XPath:
XmlNode node = a.SelectSingleNode("..");
In terms of flexibility, the first approach requires the variable a to already be an XmlAttribute or requires you to cast it to one, but it gives you an XmlElement without requiring an explicit cast.
In contrast, a only has to be an XmlNode to use the second approach, but the return value on the method is also an XmlNode.
This SO thread should answer your question
Search XML file for nodes with specific attribute value in .NET 2.
XPath is also an option, because after you get all elements that match you can use Linq to get the specific node that you're interested in.

I'm trying to find a XML node by searching for an attribute using a substring

First I'm a newbee to C# and XML parsing so please forgive me if my terminology is incorrect. I'm trying to find a node by searching for a particular attribute and value. It will work if the value is exact. I need to be able to search using a substring of the entire attribute value. Here is what I have so far...
XmlDocument doc1 = new XmlDocument();
doc1.Load("DVDCollectionExample.xml");
// Create an XmlNamespaceManager to resolve the default namespace.
XmlNamespaceManager nsmgr1 = new XmlNamespaceManager(doc1.NameTable);
nsmgr1.AddNamespace("bk1", "urn:dvd-schema");
// Select the DVD
XmlNode DVD;
XmlElement root1 = doc1.DocumentElement;
//DVD = root1.SelectSingleNode("descendant::bk1:DVD[bk1:Notes='[filepath disc=2]movies\\Godzilla\\video_ts\\video_ts.ifo[/filepath]'])", nsmgr1);
DVD = root1.SelectSingleNode("descendant::bk1:DVD[bk1:Notes=Contains(name(),'Godzilla')]", nsmgr1);
The last commented out line will work because it has the exact text of the Notes attribute.
Thanks in advance

Change the XPath-root of an XmlDocument in .net (C#)?

When selecting from an XmlDocument by e.g. the XPath-method SelectSingleNode we get an XmlNode that consist of the first matching node, lets call it <node1>. If we do further selection on <node1> then one might expect that the XPath-root now is this node, but this is incorrect, the root is still the same as in the original XmlDocument. Here's an example:
XmlDocument xd = new XmlDocument();
xd.LoadXml(#"<root>
<subroot>
<elm>test1</elm>
<elm>test2</elm>
<elm>test3</elm>
</subroot>
</root>");
XmlNode xnSubRoot = xd.SelectSingleNode("/root/subroot");
//This is the XPath I want to be able to use, but it returns null.
XmlNode xnElm = xnSubRoot.SelectSingleNode("/subroot/elm");
//This works, but the XPath-root is the same as in the original document.
xnElm = xnSubRoot.SelectSingleNode("/root/subroot/elm");
Is there any way to "fix" the root of xnSubRoot so that I can use the XPath I want? The reason for my question is because I have a case where I'm calling a webservice that returns an XmlNode where the OuterXml-property shows a structure of "/Data/SubElement/..." and so on, but when running XPath "/Data" then null is returned, only "/SubElement" works, i.e. the XPath-root seems to be one level lower than the actual document-root.
I'm sure there is a perfectly reasonable explanation for this, or that I'm missing something vital. However I really can't seem to find anything, even though I've read http://msdn.microsoft.com/en-us/library/d271ytdx(VS.80).aspx.
N.B. I do realize that it would be possible to use the XPath "//subroot/elm", but then I might also get other elements further down in the XML structure.
Since your selecting from the Root/SubElement Try this:
XmlNode xnElm = xnSubRoot.SelectSingleNode("elm");
It will return the first child elm node of the current node.
Edit (from additionals informations provided in comments):
In this specific case, you are obtaning a XmlNode (which is your Data node) from a WebService call. All XPath requests on that XmlNode will be relative to it.
I would suggest that you modify all your XPaths to use a selector like webServiceNode.SelectSingleNode("SubElement/SubSubElement"); . There is no reason to specify absolute XPaths queries here.
This works:
XmlNode xnSubRoot = xd.SelectSingleNode("/root/subroot");
XmlNode xnElm = xnSubRoot.SelectSingleNode("elm");
And so does this:
XmlNode xnRoot = xd.SelectSingleNode("/root");
XmlNode xnElm = xnRoot.SelectSingleNode("subroot/elm");

Adding element to existing XML node

Where am i going wrong???
I have an xml file with OppDetails as a tag already as shown below
<OppDetails>
<OMID>245414</OMID>
<ClientName>Best Buy</ClientName>
<OppName>International Rate Card</OppName>
<CTALinkType>AO,IO,MC,TC</CTALinkType>
</OppDetails>
</OppFact>
Now i am trying to add another element to it but getting an error in AppendChild method please help
XmlNode rootNode = xmlDoc.SelectSingleNode("OppDetails");
XmlElement xmlEle = xmlDoc.CreateElement("CTAStartDate");
xmlEle.InnerText = ExcelUtility.GetCTAStartDate();
rootNode.AppendChild(xmlEle);
xmlDoc.Save("C:\\test.xml");
XmlElement xmlEle = xmlDoc.DocumentElement["OppDetails"];
XmlElement eleNew = xmlDoc.CreateElement("CTAStartDate");
eleNew.InnerText = ExcelUtility.GetCTAStartDate();
xmlEle.AppendChild(eleNew);
xmlDoc.Save("C:\\test.xml");
It is hard to tell without a full sample, but a common reason for SelectNodes / SelectSingleNode returning null is xml namespaces. If you xml makes use of element namespaces, you'll probably need to use an XmlNamespaceManager along with your query, and define a suitable alias for the namespace you want.
Is rootNode null?
From MSDN on SelectSingleNode:
The first XmlNode that matches the
XPath query or a null reference
(Nothing in Visual Basic) if no
matching node is found.
If rootNode is null, it indicates that the node could not be found, and trying to use the null rootNode would cause the exception you are seeing.
The exception you've reported means that you have not located the root element. When SelectSingleNode can't find the requested node, it returns null. You didn't check for that.
Read root node and add the new element in to the root node. I think you are trying to append in XML document.

Append an xml document to an xml node in C#?

How can I append an XML document to an xml node in c#?
An XmlDocument is basically an XmlNode, so you can append it just like you would do for any other XmlNode. However, the difference arises from the fact that this XmlNode does not belong to the target document, therefore you will need to use the ImportNode method and then perform the append.
// xImportDoc is the XmlDocument to be imported.
// xTargetNode is the XmlNode into which the import is to be done.
XmlNode xChildNode = xSrcNode.ImportNode(xImportDoc, true);
xTargetNode.AppendChild(xChildNode);
Yes:
XmlNode imported = targetNode.OwnerDocument.ImportNode(otherDocument.DocumentElement, true);
targetNode.AppendChild(imported);
I think this creates a clone of your document though.
Perhaps like this:
XmlNode node = ...... // belongs to targetDoc (XmlDocument)
node.AppendChild(targetDoc.ImportNode(xmlDoc.DocumentElement));
Marc
Let's say you have the following construction:
The following structure is stored in an XmlElement named xmlElement:
</root>
and the following structure is stored in an XmlNode object named FooNode;
<foo>
<bar>This is a test</bar>
<baz>And this is another test</baz>
</foo>
Then you do the following:
XmlNode node = doc.ImportNode(FooNode.SelectSingleNode("foo"), true);
xmlElement.AppendChild(node);
Hope it helps someone
Once you have the root node of the XML document in question you can append it as a child node of the node in question. Does that make sense?

Categories

Resources