How to update XML file content with XDocument - c#

I have a XML file that contains this:
<?xml version="1.0" encoding="utf-8" ?>
<TokenToCardMapping>
<pair key ="2313123124122512" value="3412412512512512"/>
<pair key ="3414125121259723" value="3749327923749723"/>
</TokenToCardMapping>
I am looking for way to add a new pair element to the TokenToCardMapping descendants with XDocument or XElement.
I have the key and value as strings and I just want to add a new pair.
if my new key and value are: 111111111111 , 222222222222 I want to update the xml to look like this:
<?xml version="1.0" encoding="utf-8" ?>
<TokenToCardMapping>
<pair key ="2313123124122512" value="3412412512512512"/>
<pair key ="3414125121259723" value="3749327923749723"/>
<pair key ="111111111111" value="222222222222"/>
</TokenToCardMapping>

It is easy with LINQ to XML
// create new element
var newElement = new XElement("pair",
new XAttribute("key","111111111111"
new XAttribute("value","222222222222"));
// load the XML Document
var xDoc = XDocument.Load("path");
// Add new element to the root element
xDoc.Root.Add(newElement);
//And save the XML file
xDoc.Save("path")
Note: You need to add a reference to System.Xml.Linq.dll from your project
And I would recommend you read the LINQ to XML tutorial for more details.

Related

How do I generate this XML in C#? [duplicate]

This question already has answers here:
Add Stylesheet reference to XML Document in Linq?
(1 answer)
Creating XDocument with xsi:schemaLocation namespace
(1 answer)
Closed last year.
I have an example XML file that I need to generate on the fly in a console application.
This is an example of the first part of the required XML document:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="ABC123.xsl" ?>
<CPPData xsi:noNamespaceSchemaLocation="CPPData_V1.14.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Envelope>
<EnvelopeNode NumOrdre="1">
</EnvelopeNode>
</Envelope>
</CPPData>
I have a method creates and returns an XElement which contains all the data required by the body of the XML (e.g. everything inside the CPPData element).
However I can't figure out how to add the following:
<?xml-stylesheet type="text/xsl" href="ABC123.xsl" ?> to the XDocument
<CPPData xsi:noNamespaceSchemaLocation="CPPData_V1.14.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> to the XElement
var xml = new XDocument();
var xp = new XProcessingInstruction(target: "xml-stylesheet", data: #"type=""text/xsl"" href=""ABC123.xsl""");
xml.Add(xp);
XNamespace ns = "http://www.w3.org/2001/XMLSchema-instance";
xml.Add(new XElement("root",
new XAttribute(ns + "noNamespaceSchemaLocation", "CPPData_V1.14.xsd"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance")
));

Access Child nodes with namespace using xpath

How can I read the content of the childnotes using Xpath?
I have already tried this:
var xml = new XmlDocument();
xml.Load("server-status.xml");
var ns = new XmlNamespaceManager(xml.NameTable);
ns.AddNamespace("ns", "namespace");
var node = xml.SelectSingleNode("descendant::ns:server[ns:ip-address]", ns)
Console.WriteLine(node.InnerXml)
But I only get a string like this:
<ip-address>127.0.0.50</ip-address><name>Server 1</name><group>DATA</group>
How can I get the values individually?
Xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<server-status xmlns="namespace">
<server>
<ip-address>127.0.0.50</ip-address>
<name>Server 1</name>
<group>DATA</group>
</server>
</server-status>
You're using XML namespaces in XPath correctly.
However, your original XPath,
descendant::ns:server[ns:ip-address]
says to select all ns:server elements with ns:ip-address children.
If you wish to select the ns:ip-address children themselves, instead use
descendant::ns:server/ns:ip-address
Similarly, you could select ns:name or ns:group elements.

How to create a dictionary and store values for the values in c#

I want to create a dictionary for the following xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<groups>
<group>
<data>Open</data>
<aggregation>5</aggregation>
</group>
</groups>
I want my dictionary to get the values as:
Open,5
Please note that 'Open' is fetched from <data>Open</data> and '5' is fetched from <aggregation>5</aggregation>.
My current code is as follows:
foreach (XmlNode group in Bugsagg)
{
XmlNode data = group.SelectSingleNode(".//data");
XmlNode aggregate = group.SelectSingleNode(".//aggregation");
if (Dict_Aggregate.ContainsKey(data.InnerText))
{
Dict_Aggregate[data.InnerText]++;
}
else
{
Dict_Aggregate.Add(data.InnerText, 1);
}
I am not getting the desired response. Please suggest where i am doing wrong.Thanks
Use XElement and LINQ to XML.
You should add
using System.Xml;
using System.Xml.Linq;
on top of your code. Then use the following
string xml = #"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?><groups><group><data>Open</data><aggregation>5</aggregation></group></groups>";
XElement xe = XElement.Parse(xml);
Dictionary<string,string> d =
xe.Elements("group")
.ToDictionary
(
x=>(string)x.Element("data"), //Key Selector
z=>(string)z.Element("aggregation")//Value Selector
);
Some people might also suggest to use an XDocument as you provide a fully qualified xml with declaration etc:
XDocument xd = XDocument.Parse(xml);
Dictionary<string,string> d =
xd.Root.Elements("group")
.ToDictionary
(
x=>(string)x.Element("data"), //Key Selector
z=>(string)z.Element("aggregation")//Value Selector
);

Serialize XML and append new elements to XML file

I have created a XML class using XSD2Code from my XML Schema. The class having a method SaveToFile. So when I am trying to add new elements and save it to the XML file it overwrites the entire content.
Does anyone have idea how to insert elements(append to the XML) to the XML file via Serialization.
eg:
<?xml version="1.0" encoding="utf-8"?>
<root>
<element>content1</element>
</root>
If this is the XML file I need to add an element and the resulting should come as like below using Serialization.
<?xml version="1.0" encoding="utf-8"?>
<root>
<element>content1</element>
<element>content2</element>
</root>
Your request would seem to be resolvable by adding another item into your List collection.
MyTypeFromXmlSchema myType = new MyTypeFromXmlSchema();
myType.MyElementItems = new List<MyElementItem>();
myType.MyElementItems.Add { new MyElementItem { value = "value1" } };
myType.MyElementItems.Add { new MyElementItem { value = "value2" } };
Then serialize type using XmlSerializer.

How to correctly parse an XML document with arbitrary namespaces

I am trying to parse somewhat standard XML documents that use a schema called MARCXML from various sources.
Here are the first few lines of an example XML file that needs to be handled...
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<marc:collection xmlns:marc="http://www.loc.gov/MARC21/slim" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.loc.gov/MARC21/slim http://www.loc.gov/standards/marcxml/schema/MARC21slim.xsd">
<marc:record>
<marc:leader>00925njm 22002777a 4500</marc:leader>
and one without namespace prefixes...
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<collection xmlns="http://www.loc.gov/MARC21/slim">
<record>
<leader>01142cam 2200301 a 4500</leader>
Key point: in order to get the XPaths to resolve further along in the program I have to go through a regex routine to add the namespaces to the NameTable (which doesn't add them by default). This seems unnecessary to me.
Regex xmlNamespace = new Regex("xmlns:(?<PREFIX>[^=]+)=\"(?<URI>[^\"]+)\"", RegexOptions.Compiled);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlRecord);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable);
MatchCollection namespaces = xmlNamespace.Matches(xmlRecord);
foreach (Match n in namespaces)
{
nsMgr.AddNamespace(n.Groups["PREFIX"].ToString(), n.Groups["URI"].ToString());
}
The XPath call looks something like this...
XmlNode leaderNode = xmlDoc.SelectSingleNode(".//" + LeaderNode, nsMgr);
Where LeaderNode is a configurable value and would equal "marc:leader" in the first example and "leader" in the second example.
Is there a better, more efficient way to do this? Note: suggestions for solving this using LINQ are welcome, but I would mainly like to know how to solve this using XmlDocument.
EDIT: I took GrayWizardx's advice and now have the following code...
if (LeaderNode.Contains(":"))
{
string prefix = LeaderNode.Substring(0, LeaderNode.IndexOf(':'));
XmlNode root = xmlDoc.FirstChild;
string nameSpace = root.GetNamespaceOfPrefix(prefix);
nsMgr.AddNamespace(prefix, nameSpace);
}
Now there's no more dependency on Regex!
If you know there is going to be a given element in the document (for instance the root element) you could try using GetNamespaceOfPrefix.

Categories

Resources