Overwrite specific XML attributes - c#

Let's say I have a file like this:
<outer>
<inner>
<nodex attr="value1">text</attr>
<nodex attr="value2">text</attr>
</inner>
</outer>
Basically what I want to do is, in C# (constrained to .net 2.0 here), this (pseudocode):
foreach node
if(node eq 'nodex')
update attr to newvalue
When complete, the xml file (on disk) should look like:
<outer>
<inner>
<nodex attr="newvalue1">text</attr>
<nodex attr="newvalue2">text</attr>
</inner>
</outer>
These two look marginally promising:
Overwrite a xml file value
Setting attributes in an XML document
But it's unclear whether or not they actually answer my question.
I've written this code in the meantime:
Here's a more minimal case which works:
public static void UpdateXML()
{
XmlDocument doc = new XmlDocument();
using (XmlReader reader = XmlReader.Create("XMLFile1.xml"))
{
doc.Load(reader);
XmlNodeList list = doc.GetElementsByTagName("nodex");
foreach (XmlNode node in list)
{
node.Attributes["attr"].Value = "newvalue";
}
}
using (XmlWriter writer = XmlWriter.Create("XMLFile1.xml"))
{
doc.Save(writer);
}
}

The fastest solution would be to use a loop with XmlTextReader/XmlTextWriter. That way you do not need to load the whole xml in memory.
In pseudocode:
while (reader.read)
{
if (reader.Node.Name == "nodex")
......
writer.write ...
}
You can check here for ideas.

Here is a sample script that can be run from LinqPad
var x = #"<outer>
<inner>
<nodex attr=""value1"">text</nodex>
<nodex attr=""value2"">text</nodex>
</inner>
</outer>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(x);
foreach (XmlNode n in doc.SelectNodes("//nodex"))
{
n.Attributes["attr"].Value = "new" + n.Attributes["attr"].Value.ToString();
}
doc.OuterXml.Dump();

As starting point you can show us what you have tried, you could use XPATH to select the nodes you want to modify, search for select node by attribute value in xpath.
After you have found the nodes you want to update you can reassign the attribute value as needed with a normal assignment.

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);

Adding info to a xml file

I have a XML file which contains about 850 XML nodes. Like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
........ 849 more
And I want to add a new Childnode inside each and every Node. So I end up like this:
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
<Description>TestDescription</Description>
</NameValueItem>
........ 849 more
I've tried the following:
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
XmlNodeList nodes = doc.GetElementsByTagName("NameValueItem");
Which gives me all of the nodes, but from here am stuck(guess I need to iterate over all of the nodes and append to each and every) Any examples?
You need something along the lines of this example below. On each of your nodes, you need to create a new element to add to it. I assume you will be getting different values for the InnerText property, but I just used your example.
foreach (var rootNode in nodes)
{
XmlElement element = doc.CreateElement("Description");
element.InnerText = "TestDescription";
root.AppendChild(element);
}
You should just be able to use a foreach loop over your XmlNodeList and insert the node into each XmlNode:
foreach(XmlNode node in nodes)
{
node.AppendChild(new XmlNode()
{
Name = "Description",
Value = [value to insert]
});
}
This can also be done with XDocument using LINQ to XML as such:
XDocument doc = XDocument.Load(xmlDoc);
var updated = doc.Elements("NameValueItem").Select(n => n.Add(new XElement() { Name = "Description", Value = [newvalue]}));
doc.ReplaceWith(updated);
If you don't want to parse XML using proper classes (i.e. XDocument), you can use Regex to find a place to insert your tag and insert it:
string s = #"<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>";
string newTag = "<Description>TestDescription</Description>";
string result = Regex.Replace(s, #"(?<=</Code>)", Environment.NewLine + newTag);
but the best solution is Linq2XML (it's much better, than simple XmlDocument, that is deprecated at now).
string s = #"<root>
<NameValueItem>
<Text>Test</Text>
<Code>Test</Code>
</NameValueItem>
<NameValueItem>
<Text>Test2</Text>
<Code>Test2</Code>
</NameValueItem>
</root>";
var doc = XDocument.Load(new StringReader(s));
var elms = doc.Descendants("NameValueItem");
foreach (var element in elms)
{
element.Add(new XElement("Description", "TestDescription"));
}
var text = new StringWriter();
doc.Save(text);
Console.WriteLine(text);

Get Child Nodes from an XML File

I have an XML File like below
<Attachment>
<FileName>Perimeter SRS.docx</FileName>
<FileSize>15572</FileSize>
<ActivityName>ActivityNamePerimeter SRS.docx</ActivityName>
<UserAlias>JameelM</UserAlias>
<DocumentTransferId>7123eb83-d768-4a58-be46-0dfaf1297b97</DocumentTransferId>
<EngagementName>EAuditEngagementNameNew</EngagementName>
<Sender>JameelM#orioninc.com</Sender>
</Attachment>
I read these xml file like below
var doc = new XmlDocument();
doc.Load(files);
foreach (XmlElement pointCoord in doc.SelectNodes("/Attachment"))
{
}
I need to get each child node value inside the Attachment node. How can i get these xml elements from the xml node list?
I need to get each child node value inside the Attachment node.
Your question is very unclear, but it looks like it's as simple as:
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
}
After all, in the document you've shown us, the Attachment is the document element. No XPath is required.
As an aside, if you're using .NET 3.5 or higher, LINQ to XML is a much nicer XML API than the old DOM (XmlDocument etc) API.
try this
var data = from item in doc.Descendants("Attachment")
select new
{
FileName= item.Element("FileName").Value,
FileSize= item.Element("FileSize").Value,
Sender= item.Element("Sender").Value
};
foreach (var p in data)
Console.WriteLine(p.ToString());
var doc = new XmlDocument();
doc.Load(files);
foreach (XmlElement pointCoord in doc.SelectNodes("/Attachment"))
{
if(pointCoord!=null)
{
var valueOfElement=pointCoord.InnerText;
}
}
if you want to run conditional logic against the element names (UserAlias, etc) then use the Name property of the XmlElement.

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();

Loading a XML, but for asp.net 2.0

I need to load an XML document into my Dictionary<string,string> object.
XML looks like:
<nodes>
<node id="123">
<text>text goes here</text>
</node>
</nodes>
How can I do this using XmlDocument?
I want readability over performance, and I find XmlReader to be hard to read b/c you have to keep checking the node type.
Assuming ID is the key and the value of the <text> node is the value, you can use LINQ:
XDocument xDoc;
using(StringReader sr = new StringReader("thexml"))
{
xDoc = XDocument.Load(sr);
}
myDictionary = xDoc.Descendants("node").ToDictionary(x => x.Attribute("id").Value, x => x.Descendants("text").First().Value);
Well, there is a reason why XML parsing has improved since 2.0, but if you just want a sample that parses that fragment without using XmlReader, this should work. I'm sure there are other ways of doing this:
XmlDocument doc = new XmlDocument();
doc.LoadXml(#"<nodes><node id=""123""><text>text goes here</text></node><node id=""321""><text>more text goes here</text></node></nodes>");
foreach (XmlNode nodes in doc.GetElementsByTagName("nodes"))
{
foreach (XmlNode node in nodes.ChildNodes)
{
XmlNodeList list = node.SelectNodes("text");
if (list.Count > 0)
{
Console.Write("{0}='{1}'\n", node.Attributes["id"].Value, list[0].InnerText);
}
}
}
Console.WriteLine("Done.");
Console.ReadKey();

Categories

Resources