How do I modify node value while iterating with XPathNodeIterator? - c#

I'm navigating XML document with XPathNodeIterator, and I want to change some nodes' values.
I can't figure out how :(
Here's the code I'm using:
XPathDocument docNav = new XPathDocument(path);
XPathNavigator nav = docNav.CreateNavigator();
nav.MoveToRoot();
XPathNodeIterator itemsIterator = nav.Select("/foo/bar/item");
while (mediumsIterator.MoveNext())
{
XPathNodeIterator subitemsIterator = itemsIterator.Current.Select("SubitemsList/name");
while (subitemsIterator.MoveNext())
{
XPathNodeIterator nodesIterator = itemsIterator.Current.Select("Param");
nodesIterator.MoveNext();
String the_params = nodesIterator.Current.Value;
// check if I need to modify nodesIterator.Current.Value
// ...
// ok I do - how?
}
}
And the XML file sample:
<?xml version="1.0" encoding="utf-8"?>
<foo>
<bar>
<item>
<Param />
<SubitemsList>
<name>name one</name>
<name>name two</name>
...
</SubitemsList>
</item>
...
</bar>
</foo>
Or maybe there's a better way to do this?

I found a way:
Replace XPathDocument with XmlDocument
When I get to the needed node
...
XmlNode node = ((IHasXmlNode)nodesIterator.Current).GetNode();
node.InnerText = "new text";

Related

RemoveChild when node is empty

I want to remove some child elements from an XML structure using RemoveChild() if a node is empty. My XML:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
<Status></Status>
</Customer>
<customer>
<Name>John</Name>
<Age></Age>
<Status></Status>
</Customer>
</Customers>
Should become:
<Customers>
<customer>
<Name>John</Name>
<Age>25</Age>
</Customer>
<customer>
<Name>John</Name>
</Customer>
</Customers>
My code so far:
XmlElement element3 = xmlDocument.CreateElement("Age");
element3.InnerText = str3;
element1.AppendChild((XmlNode)element3);
XmlElement element4 = xmlDocument.CreateElement("Status");
element4.InnerText = str4;
element1.AppendChild((XmlNode)element4);
How can I remove the empty node resp. nodes if there is more than one empty node?
Add a condition to only create the element if you need to:
if (!string.IsNullOrEmpty(status))
{
XmlElement statusElement = xmlDocument.CreateElement("Status");
statusElement.InnerText = status;
customerElement.AppendChild((XmlNode)statusElement);
}
Or if you need to remove it after it's already created (e.g. because you get XML from an external source with an empty Status), use the same sort of condition to remove it:
if (!string.IsNullOrEmpty(status))
{
customerElement.RemoveChild(statusElement);
}
That is because you are trying to remove a child element that simply does not exist. You must understand that in this context, the RemoveChild() method expects a reference to an existing node within the parent's children.
If i were to use your code sample above and create a standalone representation of this, it would look like this:
XmlDocument doc = new XmlDocument();
XmlElement element1 = doc.CreateElement("Customer");
XmlElement element2 = doc.CreateElement("Name");
element2.InnerText = "John";
element1.AppendChild(element2);
XmlElement element3 = doc.CreateElement("Age");
element3.InnerText = "25";
element1.AppendChild(element3);
XmlElement element4 = doc.CreateElement("Status");
element4.InnerText="";
element1.AppendChild(element4);
doc.AppendChild(element1);
element1.RemoveChild(element1.SelectSingleNode("Status"));
Using Linq-to-XML:
If you want nodes like:
<a>
<b>
<c></c>
</b>
</a>
to become:
<a />
Use:
XElement root = XElement.Load(file);
root.Descendants().Reverse().ToList().ForEach(x =>
{
if (x.IsEmpty)
x.Remove();
});
But if you want it to be:
<a>
<b />
</a>
Remove the .Reverse()

Xml parser doesn't work

<?xml version="1.0" encoding="utf-8"?>
<response list="true">
<audio>
<aid>253663595</aid>
<artist>Example</artist>
<duration>389</duration>
<lyrics_id>57485771</lyrics_id>
<genre>18</genre>
</audio>
<audio>
<aid>253663595</aid>
<artist>Example1</artist>
<duration>400</duration>
<lyrics_id>57485772</lyrics_id>
<genre>20</genre>
</audio>
</response>
Source code
XmlDocument allAudio = new XmlDocument();
allAudio.Load(#"e:\Audio.xml");
StreamWriter write_text = File.CreateText(#"e:\Audio.txt");
XmlNodeList audioNodes = allAudio.GetElementsByTagName("audio");
foreach (XmlNode audioNode in audioNodes)
{
XmlNode artistNode = audioNode["artist"];
write_text.WriteLine(String.Format("{0}", artistNode.Value));
}
write_text.Close();
Hi, I can't parse xml. I want write some node values in file, but as result I get an empty txt file.
You want: artistNode.InnerText
Not: artistNode.value

C# remove attribute from root node

I tries to parse a XML file (get it from Dependacy Graph in VS 2012).
Here is sample of my .xml file
<?xml version="1.0" encoding="utf-8"?>
<DirectedGraph xmlns="http://schemas.microsoft.com/vs/2009/dgml">
<Nodes>
<Node Id="#101" Category="CodeSchema_ProjectItem" FilePath="$(ProgramFiles)\windows kits\8.0\include\um\unknwnbase.h" Label="unknwnbase.h" />
<Node Id="#103" Category="CodeSchema_ProjectItem" FilePath="$(ProgramFiles)\windows kits\8.0\include\shared\wtypesbase.h" Label="wtypesbase.h" />
in here, I needs to remove attribute "xmlns" from DirectedGraph.
here's my source to remove this
XmlNodeList rootNode = xmlDoc.GetElementsByTagName("DirectedGraph");
foreach (XmlNode node in rootNode)
{
node.Attributes.RemoveNamedItem("xmlns");
}
but this code doesn't work. If I don't delete this I can't select node like
XmlNodeList nodes = xmlDoc.DocumentElement.SelectNodes("/DirectedGraph/Nodes/Node");
What should I do?
If you like you can work with the namespace instead of removing the declaration:
var xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<DirectedGraph xmlns=""http://schemas.microsoft.com/vs/2009/dgml"">
<Nodes>
<Node Id=""#101"" Category=""CodeSchema_ProjectItem"" FilePath=""$(ProgramFiles)\windows kits\8.0\include\um\unknwnbase.h"" Label=""unknwnbase.h"" />
<Node Id=""#103"" Category=""CodeSchema_ProjectItem"" FilePath=""$(ProgramFiles)\windows kits\8.0\include\shared\wtypesbase.h"" Label=""wtypesbase.h"" />
</Nodes>
</DirectedGraph>";
var doc = new XmlDocument();
doc.LoadXml(xml);
var manager = new XmlNamespaceManager(doc.NameTable);
manager.AddNamespace("d", "http://schemas.microsoft.com/vs/2009/dgml");
var nodes = doc.DocumentElement.SelectNodes("/d:DirectedGraph/d:Nodes/d:Node", manager);
Console.WriteLine(nodes.Count);
Use:
private static XElement RemoveAllNamespaces(XElement xmlDocument)
{
if (!xmlDocument.HasElements)
{
XElement xElement = new XElement(xmlDocument.Name.LocalName);
xElement.Value = xmlDocument.Value;
foreach (XAttribute attribute in xmlDocument.Attributes())
xElement.Add(attribute);
return xElement;
}
return new XElement(xmlDocument.Name.LocalName, xmlDocument.Elements().Select(el => RemoveAllNamespaces(el)));
}
Taken from: How to remove all namespaces from XML with C#?.
You might also want to check out: XmlSerializer: remove unnecessary xsi and xsd namespaces.

add XML node with formatting

I am adding a node to the XML file, but I need it to be properly formatted. Could you assist with it?
String newFile = System.IO.Path.GetFileName(textBox1.Text);
//file name
string filename = #"palette.xml";
XmlDocument doc = new XmlDocument();
doc.Load(filename);
//create node and add value
XmlNode node = doc.CreateNode(XmlNodeType.Element, "item", null);
//create title node
XmlNode nodeTitle = doc.CreateElement("name");
//add value for it
nodeTitle.InnerText = #"<![CDATA["+newFile+"]]>";
//create Url node
XmlNode nodeUrl = doc.CreateElement("imgfile");
nodeUrl.InnerText = newFile;
//add to parent node
node.AppendChild(nodeTitle);
node.AppendChild(nodeUrl);
//add to elements collection
doc.DocumentElement.AppendChild(node);
//save back
doc.Save(filename);
The XML should be looking like that:
<item>
<name><![CDATA[panda.gif]]></name>
<imgfile>panda.gif</imgfile>
</item>
but it look like that:
<item>
<name><![CDATA[panda.gif]]></name>
<imgfile>panda.gif</imgfile>
</item>
There is a method you can use to wrap cdata it is.
XMLNode.AppendChild( XMLDocument.CreateCDataSection( newFile ) );
It XMLDocument.CreateCDataSection returns XmlCDataSection object which you can append to your node and it will wrap your file in CDATA.
Check this out for more information: http://msdn.microsoft.com/en-us/library/system.xml.xmldocument.createcdatasection.aspx
CDATA is considered a node, not an inner text
<item>
<name>
<![CDATA[panda.gif]]>
</name>
<imgfile>panda.gif</imgfile>
</item>
So:
XmlElement nodeTitle = document.CreateElement("name");
XmlCDataSection CDATA = document.CreateCDataSection("panda.gif");
nodeTitle.AppendChild(CDATA);
node.AppendChild(nodeTitle);

manipulation of xml using c#

If I want to add, update or delete node in the xml using c#, how can it be done? My xml is shown below. I dont want transactionID node. I want to add a node called <Transformation>XML</Transformation> after corelationID node.
<?xml version="1.0" ?>
<GovTalkMessage xmlns="http://www.govtalk.gov.uk/CM/envelope">
<EnvelopeVersion>2.0</EnvelopeVersion>
<Header>
<MessageDetails>
<Class>HMRC-VAT-DEC</Class>
<Qualifier>poll</Qualifier>
<Function>submit</Function>
<TransactionID />
<CorrelationID>1B93D48C02D740C6B79DE68A27F3ADE5</CorrelationID>
<ResponseEndPoint PollInterval="10">https://secure.dev.gateway.gov.uk/poll</ResponseEndPoint>
<GatewayTimestamp>2011-04-05T07:41:43.018</GatewayTimestamp>
</MessageDetails>
<SenderDetails />
</Header>
<GovTalkDetails>
<Keys />
</GovTalkDetails>
<Body />
</GovTalkMessage>
The easiest thing to use would be LINQ to XML. For example:
XDocument doc = XDocument.Load("file.xml");
XNamespace ns = "http://www.govtalk.gov.uk/CM/envelope";
// Remove TransationID
XElement transactionElement = doc.Descendants(ns + "TransactionID").Single();
transactionElement.Remove();
// Add XML:
XElement correlationElement = doc.Descendants(ns + "CorrelectionID").Single();
XElement newElement = new XElement(ns + "XML");
correlationElement.AddAfterSelf(newElement);
// Save back
doc.Save("new-file.xml");
//Load the XML
XmlDocument documentXML = new XmlDocument();
documentXML.Load(Server.MapPath("AddDeleteUpdate.xml"));
XmlNamespaceManager xmlns = new XmlNamespaceManager(documentXML.NameTable);
xmlns.AddNamespace("bk", "http://www.govtalk.gov.uk/CM/envelope");
//Identify the parent node i.e <MessageDetails>
XmlNode nodeMessage = documentXML.SelectSingleNode("//bk:GovTalkMessage/bk:Header/bk:MessageDetails", xmlns);
//Delete the node.
XmlNode nodeTransactionID = documentXML.SelectSingleNode("//bk:GovTalkMessage/bk:Header/bk:MessageDetails/bk:TransactionID", xmlns);
nodeMessage.RemoveChild(nodeTransactionID);
//Create the new XML noded to be added.
XmlNode controlAttrNode = null;
controlAttrNode = documentXML.CreateElement("Transformation");
controlAttrNode.InnerText = "XML";
controlAttrNode.Attributes.RemoveAll();
//Get the node object to where it need to be added.
XmlNode nodeCorrelation = documentXML.SelectSingleNode("//bk:GovTalkMessage/bk:Header/bk:MessageDetails/bk:CorrelationID", xmlns);
//Insert the node after.
nodeMessage.InsertAfter(controlAttrNode, nodeCorrelation);
documentXML.Save(Server.MapPath("AddDeleteUpdate.xml"));
You'll need
XMLNode.InsertAfter(newChildNode,referenceChildNode)
This should kickstart you:
http://msdn.microsoft.com/en-US/library/system.xml.xmlnode.insertafter%28v=VS.80%29.aspx

Categories

Resources