How to Remove Root Element in C#/ - c#

I'm new to XML & C#.
I want to remove root element without deleting child element.
XML file is strudctured as below.
<?xml version="1.0" encoding="UTF-8"?>
<dataroot generated="2013-07-06T20:26:48" xmlns:od="urn:schemas-microsoft-com:officedata">
<MetaDataSection>
<Name>KR04</Name>
<XMLCreationDate>02.05.2013 9:52:41 </XMLCreationDate>
<Address>AUTOMATIC</Address>
<Age>22</Age>
</MetaDataSection>
</dataroot>
I want to root element "dataroot", so it should look like below.
<?xml version="1.0" encoding="UTF-8"?>
<MetaDataSection>
<Name>KR04</Name>
<XMLCreationDate>02.05.2013 9:52:41 </XMLCreationDate>
<Address>AUTOMATIC</Address>
<Age>22</Age>
</MetaDataSection>
Deleting child elements look like easy, but I don't know how to delete root element only.
Below is the code I've tried so far.
XmlDocument xmlFile = new XmlDocument();
xmlFile.Load("path to xml");
XmlNodeList nodes = xmlFile.SelectNodes("//dataroot");
foreach (XmlElement element in nodes)
{
element.RemoveAll();
}
Is there a way to remove root element only? without deleting child elements?
Thank you in advnace.

Rather than trying to actually remove the root element from an existing object, it looks like the underlying aim is to save (or at least access) the first child element of the root element.
The simplest way to do this is with LINQ to XML - something like this:
XDocument input = XDocument.Load("input.xml");
XElement firstChild = input.Root.Elements().First();
XDocument output = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
firstChild);
output.Save("output.xml");
Or if you don't need the XML declaration:
XDocument input = XDocument.Load("input.xml");
XElement firstChild = input.Root.Elements().First();
firstChild.Save("output.xml");

if you need to do in c# coding means
Solution
foreach (XElement item in Element.Descendants("dataroot").ToList())
{
item.ReplaceWith(item.Nodes());
}

Related

C# How remove single xml parent element node without removing the contents inside the parent node

I am new to C#, kindly help me. How to remove the single xml element node 'PaymentRecord' and content inside that should not get deleted.
<Payments>
<PaymentRecord>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</PaymentRecord>
</Payments>
I need to remove "PaymentRecord" element from the XML. I need like below
<Payments>
<PayId>2031</PayId>
<Reference>Policy03</Reference>
<StatusCode>ACV</StatusCode>
<MethodDetail>
<PaymentMethodDetail>
<CardPaymentDetails>
<CardHolderName>abcded</CardHolderName>
<CardTransactionDetails>
<StoredCard>N</StoredCard>
</CardTransactionDetails>
</CardPaymentDetails>
</PaymentMethodDetail>
</MethodDetail>
<CurrencyCode>USD</CurrencyCode>
</Payments>
I have tried my below code, but its deleting the complete node which I don't want to do :- here 'queuePayload' is the xml element
XmlNodeList payloadRecordList = queuePayload.SelectNodes("//Payments/PaymentRecord");
foreach (XmlElement singleNode in payloadRecordList)
{
XmlHelper.removeElem((XmlElement)singleNode.ParentNode, "//PaymentRecord");
XmlDocument xmlDoc = singleNode.OuterXml;
// my remaining logic goes based on "xmldoc" value - I will inserting this data to table
}
You can use System.Xml.Linq with its XDocument to achiev this. Load the input and create a new document out of it like:
XDocument inputDoc = XDocument.Load(inputFile, LoadOptions.None);
XDocument outputDoc = new XDocument();
var elements = inputDoc.Element("Payments").Elements().Select(pr => pr.Elements());
XElement newElement = new XElement("Payments");
foreach (var element in elements)
{
newElement.Add(element);
}
outputDoc.Add(newElement);
Console.WriteLine(outputDoc.ToString());
I think #Fructzwerg is slightly overcomplicating it.
You can remove the PaymentRecord node and add all its children to the root in one go.
var xDoc = XDocument.Load(filePath);
var paymentRecord = xDoc.Root.Element("PaymentRecord");
var nodes = xDoc.Root.Element("PaymentRecord").Elements();
paymentRecord.Remove();
xDoc.Root.Add(nodes);
Console.WriteLine(xDoc.ToString());
dotnetfiddle

Delete Attribute of Xml node c#

I have a XML file like this:
<?xml version="1.0" encoding="utf-8"?>
<ApplicationConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd">
<ServerConfiguration>
<SecurityPolicies>
<ServerSecurityPolicy>
<SecurityMode>None_1</SecurityMode>
</ServerSecurityPolicy>
</SecurityPolicies>
</ServerConfiguration>
</ApplicationConfiguration>
What I want is to add more node named ServerSecurityPolicy by code.
Then I use this code:
string docaddress = "D:\\abc.xml";
XDocument doc = XDocument.Load(docaddress);
var root = doc.Root;
var these = root.Descendants().Where(p => p.Name.LocalName == "SecurityPolicies");
XElement addelement = new XElement("ServerSecurityPolicy");
addelement.Add(new XElement("SecurityMode", "None_1"));
foreach (var elem in these)
{
elem.Add(addelement);
}
doc.Save(docaddress);
It actually works, but the newly added node is something like this:
<ServerSecurityPolicy xmlns="">
<SecurityMode>None_1</SecurityMode>
</ServerSecurityPolicy>
I don't want the attribute "xmlns", then I try to delete it by something like this:
var these2 = root.Descendants().Where(p => p.Name.LocalName == "ServerSecurityPolicy");
foreach (var elem in these2)
{
label2.Text += elem.Attribute("xmlns").Name.LocalName;
elem.Attribute("xmlns").Remove();
}
The label2.Text shows "xmlnsxmlnsxmlsn..." so that I think the elem.Attribute("xmlns") has pointed to the attributes I want to delete, but the Remove() not work.
Can you suggest me some ways to delete the attribute or add node without attribute?
Thank you
The reason you're getting an empty attribute - which xmlns="" refers to - is because your document's root node belongs to the namespace xsi. When you're adding a node without a namespace - as you're doing in your example - you're not actually binding it to the xsi namespace.
To make your node part of the root namespace, replace
new XElement("ServerSecurityPolicy")
with
new XElement("ServerSecurityPolicy",
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"))
The problem is that the element you want to create is actually in the http://opcfoundation.org/UA/SDK/Configuration.xsd namespace, which is the default for the document because of this part of the root element:
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
You can create an element in that namespace easily:
XNamespace configNs = "http://opcfoundation.org/UA/SDK/Configuration.xsd";
var these = root.Descendants(configNs + "ServerSecurityPolicy");
When you add that to your document, you'll find it won't add the xmlns="" part, which was present because you were adding an element without a namespace.
I'd also suggest using the namespace to find elements too:
XNamespace configNs = "http://opcfoundation.org/UA/SDK/Configuration.xsd";
var these = root.Descendants(configNs + "SecurityPolicies");
That's much cleaner than just using the local name, in my view.

Iterating through XML file with XDocument returns element with no attributes

I'm iterating through all the child elements of this XML file:
<?xml version="1.0" encoding="utf-8"?>
<users>
<user name="SemiViral" access="2" />
</users>
with this code:
XDocument doc = XDocument.Load("Users.xml");
Console.WriteLine(doc.Descendants("users").Count());
foreach (XElement u in doc.Descendants("users")) {
Console.WriteLine(u.Attributes().Count());
}
but the output from the WriteLine is 0, and similarly empty if I try referencing the attributes directly. Counting the descendants returns 1 and when I added inner contents to the single child element, it was able to output those. So I know that it's the correct element, it's simply not accessing the attributes for some reason.
Here is a code to do what you are trying to do. You were not getting results because you were only looking for users elements (doc.Descendants("users")). The element that you are looking for is at the next level of the xml. If you debugged your code you would have spotted it.
XDocument doc = XDocument.Load("Users.xml");
Console.WriteLine(doc.Descendants("users").Descendants().Count());
foreach (XElement u in doc.Descendants("users").Descendants())
{
Console.WriteLine("value of the attribute is " + u.Attributes("access").First().Value);
}

How to get specific children of a xml element?

I am loading a xml document and I am having a foreach loop in its elements and I want to select child elements named tag in it.
This is the xml file:
<?xml version="1.0" encoding="utf-8"?>
<view>
<tag>
<name>content</name>
<tag>
<name>div</name>
</tag>
</tag>
</view>
And this is the code:
string xmlString = System.IO.File.ReadAllText(HttpContext.Current.Server.MapPath("~/xml/xml.xml"));
XDocument doc = XDocument.Parse(xmlString);
XElement xmlElement = doc.Element("view");
foreach (var tagItem in xmlElement.Descendants("tag"))
{
//do something
}
The code written in foreach loop would contain all of tag elements in any depth, but I want to get the first depth ones(the children).
How to do this with linq?
Assuming the desired elements are always children of the <view> element you can use:
XElement xmlElement = doc.Element("view");
foreach (var tagItem in xmlElement.Elements("tag"))
{
//do something (only direct children)
}
There is nothing more to be done to get the desired elements. You can then however implement your "do something" with Linq, for example:
XElement firstElem = xmlElement.Elements("tag").OrderBy(e => e.Name).First();

inserting xml element into multiple nodes

I have the following XML
<ROOT>
<FSM338_Container>
<FSM338_Details>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<CASHBREAK>199</CASHBREAK>
<CASHLUNCH>199</CASHLUNCH>
</FSM338_Details>
<FSM338_Details>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<CASHBREAK>199</CASHBREAK>
<CASHLUNCH>199</CASHLUNCH>
</FSM338_Details>
</FSM338_Container>
<BillingReport>
<RunDate>2013-05-29 09:43:00</RunDate>
<Uic>21690</Uic>
<Date>2013-06-10 00:00:00</Date>
<gaindacd>1</gaindacd>
<docnum>07000F</docnum>
</BillingReport>
<DataElements>
<unitid>12345</unitid>
<fbocost>0.00</fbo>
</DataElements>
</ROOT>
I need to load the xml doc and add in several elements whenever I find the element named "Uic" . In short if I find "Uic" add in the element <someElement>my stuff here</someElement> at the same level as UIC at all locations.
I'Ve used
XmlDocument xDoc = new XmlDocument();
xDoc.Load(#"path_to_xml.xml");
list = xDoc.GetElementsByTagName("Uic");
I used insertBefore to add in my element but I can get it to copy to only the first element
You can use SelectNodes() method of XmlNode which accepts xpath expression.
XmlNodeList nodes = xDoc.DocumentElement.SelectNodes("Uic");
foreach(XmlNode node in nodes) {
XmlElement element = xDoc.CreateElement("SomeElement");
element.InnerText = "anything";
node.ParentNode.AppendChild(element);
}

Categories