Adding Xml Attribute to All elements except root Node - c#

I am trying to add new attribute to my xml files in c#. my xml file format is shown below:
<Root MessageOfRoot="Welcome to Xml">
<Header Size="36">
<Parameter Name="ID" Index="0" Value="23" />
<Parameter Name="Name" Index="4" Value="Uncle Bob" />
<Parameter Name="Number" Index="8" Value="4" />
</Header>
<Body Size="0">
<Parameter Index="0" UnitNumber="0" Name="UnitBarcode" Type="Integer" />
<Parameter Index="4" PromotionId="0" Name="PromotionalUnit" Type="Integer" />
</Body>
</Root>
I want to add new attribute my xml file which should be like:
<Root MessageOfRoot="Welcome to Xml">
<Header Size="36" NewAttr="1">
<Parameter Name="ID" Index="0" Value="23" NewAttr="1"/>
<Parameter Name="Name" Index="4" Value="Uncle Bob" NewAttr="1"/>
<Parameter Name="Number" Index="8" Value="4" NewAttr="1"/>
</Header>
<Body Size="0" NewAttr="1">
<Parameter Index="0" UnitNumber="0" Name="UnitBarcode" Type="Integer" NewAttr="1"/>
<Parameter Index="4" PromotionId="0" Name="PromotionalUnit" Type="Integer" NewAttr="1"/>
</Body>
</Root>
To do that i write the following code but i am having problem with adding newAttr to all nodes. How can i add NewAttr to my new xml file?
XmlDocument doc = new XmlDocument();
doc.Load("Path of xml");
XmlAttribute NewAttr = doc.CreateAttribute("NewAttr ");
countAttr.Value = "1";
XmlWriter writer = XmlWriter.Create("output.xml", settings);

You can use the following command to load the XML file:
XDocument doc = XDocument.Load(#"C:\Users\myUser\myFile.xml");
Then you can invoke a function that recursively accesses all nodes of the XML starting from the children nodes of the Root element:
AddNewAttribute(doc.Root.Elements());
The function can be like so:
public static void AddNewAttribute(IEnumerable<XElement> elements)
{
foreach (XElement elm in elements)
{
elm.Add(new XAttribute("newAttr", 1));
AddNewAttribute(elm.Elements());
}
}
Finally, you can save the XML back to the original file using:
doc.Save(#"C:\Users\myUser\myFile.xml");

Related

How to parse XML file in c#

I have a XML that has a structure similar to this one:
<?xml version="1.0" encoding="UTF-8"?>
<CompanyName>
<AttrContainer>
<Attr type="String">
<Name value="'Name'" />
<Value value="'AttrContainer'" />
</Attr>
<SubContainer>
<AttrContainer value="'WSSMetadata'" />
<AttrContainer>
<Attr type="String">
<Name value="'Name'" />
<Value value="'AttrContainer'" />
</Attr>
<SubContainer>
<WSSMetadata value="'afe2e194-0ce7-4bfc-b446-9623e4fe7189'" />
<AttrContainer>
<Attr type="String">
<Name value="'Name'" />
<Value value="'WSSMetadata'" />
</Attr>
<Attr type="Uuid">
<Name value="'scanID'" />
<Value value="afe2e194-0ce7-4bfc-b446-9623e4fe7189" />
</Attr>
<Attr type="String">
<Name value="'imagePath'" />
</Attr>
<Attr type="String">
<Name value="'imagePathHD'" />
</Attr>
<Attr type="String">
<Name value="'imagePathThumbnail'" />
</Attr>
<Attr type="String">
<Name value="'imagePathGrey'" />
<Value value="'Images/afe2e194-0ce7-4bfc-b446-9623e4fe7189_grey.jpg'" />
</Attr>
<Attr type="String">
<Name value="'imagePathGreyHD'" />
<Value value="'Images/afe2e194-0ce7-4bfc-b446-9623e4fe7189_grey_hd.jpg'" />
</Attr>
<Attr type="String">
<Name value="'imagePathGreyThumbnail'" />
<Value value="'Images/afe2e194-0ce7-4bfc-b446-9623e4fe7189_grey_thumbnail.jpg'" />
</Attr>
</AttrContainer>
</SubContainer>
</AttrContainer>
</SubContainer>
</AttrContainer>
</CompanyName>
and I am trying to parse it using this code (Linq to XML)
var xmlContent = File.ReadAllText(filePathName);
var doc = XDocument.Parse(xmlContent);
var attr = doc.Root.Elements("CompanyName");
var x = attr.ToList();
but it x has no element.
My questions:
What is wrong with this code that I am not able to get the CompanyName element?
How can I get list of all <SubContainer> elements?
When I got the list of <SubContainer> elements, how can I read read and change its content?
I think you want this instead:
var attr = doc.Root.Elements("AttrContainer");
.Elements returns child elements of that name. CompanyName is you root node, and you're trying to search for its children which are AttrContainer.
What is wrong with this code that I am not able to get the companyname element?
The root element of your xml is CompanyName. So what your code is doing, it's essentially asking 'give me all CompanyName elements that are children of my root CompanyName element'. Hence the list is empty.
how can I get list of all SubContainer elements.
You can use
var subContainers = doc.Root.Descendants("SubContainer");
when I got the list of SubContainer elements, how can I read read and change its content?
foreach (var subContainer in subContainers)
{
foreach (var attrContainer in subContainer.Elements("AttrContainer"))
{
var attr = attrContainer.Elements("Attr").FirstOrDefault();
if (attr != null)
{
var oldValue = attr.Attribute("type").Value;
attr.Attribute("type").Value = "something completely different";
}
}
}
This reads and changes the type on each first Attr element (assuming one exists) in all AttrContainers in all SubContainers - hopefully you can derive something meaningful out of that.
doc.Root returns the element <CompanyName>, so further selecting elements named CompanyName won't return any elements. You're effectively trying to select all <CompanyName> elements that are children of <CompanyName>.
This code will select all <SubContainer> elements no matter their depth. I'm suggesting this because your example XML has several <SubContainer> elements.
// Read all Attr elements
IEnumerable<XElement> subContainerElements = doc.Root.Descendants("SubContainer");
foreach (XElement subContainerElement in subContainerElements)
{
// Work with <SubContainer> element here
}

Inserting Some lines to an xml file in c#

Hi I need to insert some lines into an xml file and save it how I should do it?
the xml file is
<?xml version="1.0" encoding="utf-8"?>
<Dashboard CurrencyCulture="en-US">
<Title Text="Dashboard" />
<DataConnections>
<DataConnection Name="Database1Connection" ProviderKey="Access2007" ConnectionString="XpoProvider=MSAccess;Provider=Microsoft.ACE.OLEDB.12.0;Mode=Share Deny None;data source=D:\Sina\Desktop\Omid\Database1.accdb;Jet OLEDB:Database Password=;">
<Parameters>
<Parameter Name="database" Value="D:\Sina\Desktop\Omid\Database1.accdb" />
<Parameter Name="read only" Value="1" />
<Parameter Name="generateConnectionHelper" Value="false" />
</Parameters>
</DataConnection>
</DataConnections>
<DataSources>
<DataSource Name="Data Source 1">
<DataProvider DataConnection="Database1Connection" SupportSql="true" />
</DataSource>
<DataSource Name="Query 2" />
</DataSources>
and I need to insert these lines
<Selection>
<Table Name="Query2">
<Columns>
<Column Name="PName" />
<Column Name="Prog" />
<Column Name="RDate" />
</Columns>
</Table>
</Selection>
between
<DataProvider DataConnection="Database1Connection" SupportSql="true">
.
.(here)
</DataProvider>
Here is a complete console application that will take the file you provided as input and build a new file with the nodes added.
NOTE: you will clearly have to make the code more dynamic as this is very static. For example, you would build the Column elements with another list and a loop likely.
class Program
{
static void Main(string[] args)
{
var doc = XDocument.Load("XMLFile1.xml");
var selection = new XElement("Selection");
var table = new XElement("Table");
table.Add(new XAttribute("Name", "Query2"));
var columns = new XElement("Columns");
var column = new XElement("Column");
column.Add(new XAttribute("Name", "PName"));
columns.Add(column);
column = new XElement("Column");
column.Add(new XAttribute("Name", "Prog"));
columns.Add(column);
column = new XElement("Column");
column.Add(new XAttribute("Name", "RDate"));
columns.Add(column);
table.Add(columns);
selection.Add(table);
var dataProvider = doc.Root.Descendants("DataProvider").First();
dataProvider.Add(selection);
doc.Save("XMLFile2.xml");
}
}
The output of the new file looks like this:
<DataSources>
<DataSource Name="Data Source 1">
<DataProvider DataConnection="Database1Connection" SupportSql="true">
<Selection>
<Table Name="Query2">
<Columns>
<Column Name="PName" />
<Column Name="Prog" />
<Column Name="RDate" />
</Columns>
</Table>
</Selection>
</DataProvider>
</DataSource>
<DataSource Name="Query 2" />
</DataSources>
Try this,
XmlDocument document = new XmlDocument();
document.Load(filename);
XmlElement childElement = document.CreateElement("child");
XmlNode parentNode = document.SelectSingleNode("root/firstLevel/parent");
parentNode.AppendChild(childElement);
A quick approach would be:
string file = "XMLFile1.xml";
string text = File.ReadAllText(file);
text = text.Replace("<DataProvider DataConnection=\"Database1Connection\" SupportSql=\"true\" />",
"<DataProvider DataConnection=\"Database1Connection\" SupportSql=\"true\">" +
"<Selection>" +
"<Table Name=\"Query2\">" +
"<Columns>" +
" <Column Name=\"PName\" />" +
"<Column Name=\"Prog\" />" +
"<Column Name=\"RDate\" />" +
"</Columns>" +
"</Table>" +
"</Selection>" +
"</DataProvider> ");
File.WriteAllText(file, text);

Swapping nodes in xmlNodeList C#

Assuming having the following xml
<test>
<step>
<var name="name1" />
<var name="name2" />
</step>
<step>
<var name="name3" />
<var name="name4" />
</step>
<step>
<var name="name5" />
<var name="name6" />
</step>
</test>
I m using XmlNodeList, seperated by "step". Is there a way to swap or replace a step directly in the xmlnodelist?
Need to make it like this:
<test>
<step>
<var name="name3" />
<var name="name4" />
</step>
<step>
<var name="name1" />
<var name="name2" />
</step>
<step>
<var name="name5" />
<var name="name6" />
</step>
</test>
You can use XDocument class instead of XMLDocument. This will swap the var nodes name3 with name6.
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
XDocument document = XDocument.Load("test.xml");
Swap("name3", "name6", document);
document.Save("test.xml");
}
static void Swap(string nameOne, string nameTwo, XDocument document)
{
var nameOneNode = document.Descendants("var").FirstOrDefault(p => p.Attribute("name").Value == nameOne);
var nameTwoNode = document.Descendants("var").FirstOrDefault(p => p.Attribute("name").Value == nameTwo);
nameOneNode.Attribute("name").Value = nameTwo;
nameTwoNode.Attribute("name").Value = nameOne;
}
}
The order of the nodes in an XML file does not necessarily have to be kept when the XML file is read. For example, if your file looks like this:
<xmlcontent>
<node value="Hello" />
<node value="World" />
</xmlcontent>
The XML read may return the nodes like this:
<xmlcontent>
<node value="World" />
<node value="Hello" />
</xmlcontent>
To apply something like an "order" to XML nodes, you need to add an attribute you can sort by, like
<xmlcontent>
<node index="1" value="Hello" />
<node index="2" value="World" />
</xmlcontent>
In that case, "swapping" two elements would come down to swapping the index values.
Finally managed to do it, here is the code:
XmlDocument xml;
XmlNodeList xmlList;
xml = new XmlDocument();
xml.Load(path);
xmlList = xml.GetElementsByTagName("step");
XmlNode refNode = xmlList[1];
XmlNode newNode = xmlList[0];
xml.DocumentElement.InsertAfter(newNode, refNode);

How to Get a specific Value of an XML Node from XDocument

I am asking essentially the same question as found in this post: How to Get XML Node from XDocument with the exception of attempting to do a one-shot return of the CData value in a single line of code. I'm attempting to get the return in the below function to work properly:
private string RetrieveFormattedString(string controlId)
{
return template.Descendants("Template")
.Where(templateNode => templateNode.Value == controlId)
.Where(tmp => tmp.Name == "Format").Select(y => y.Value).ToString();
}
I have the following XML below:
<?xml version="1.0" encoding="utf-8" ?>
<Templates>
<Template>
<Name>NodeName1</Name>
<Parameter Type="TextBox" Name="conferenceID">{__otcConferenceID__}</Parameter>
<Parameter Type="TextBox" Name="conferenceCode">{__otcConferenceCode__}</Parameter>
<Format>
<![CDATA[ <b>NodeName1</b><br /> <table><tr><td>iPhone</td><td>{__otcConferenceID__},#,{__otcConferenceCode__}</td></tr></table>]]>
</Format>
</Template>
<Template>
<Name>NodeName2</Name>
<Parameter Type="TextBox" Name="conferenceID">{__otcConferenceID__}</Parameter>
<Parameter Type="TextBox" Name="conferenceCode">{__otcConferenceCode__}</Parameter>
<Format>
<![CDATA[ <b>NodeName2</b><br /> <table><tr><td>iPhone</td><td>{__otcConferenceID__},#,{__otcConferenceCode__}</td></tr></table>]]>
</Format>
</Template>
</Templates>
I know I'm doing this incorrectly, and was hoping to get a larger set of eyes on it.
private string RetrieveFormattedString(XDocument xDoc, string nodeName)
{
return xDoc.Descendants("Template")
.First(t => t.Element("Name").Value == nodeName)
.Element("Format").Value;
}

select value of attribute by linq to xml

in my xml file how i can select the value for attributes TagId in ServiceAssignment elements by linq to xml
Note : this xml in a String Property not in xml file
<AnchoredXml xmlns="urn:schema:Microsoft.Rtc.Management.ScopeFramework.2008" SchemaWriteVersion="1">
<Key ScopeClass="Global">
<SchemaId Namespace="urn:schema:Microsoft.Rtc.Management.Settings.ServiceAssignment.2008" ElementName="ServiceAssignments" />
<AuthorityId Class="Host" InstanceId="00000000-0000-0000-0000-000000000000" />
</Key>
<Dictionary Count="1">
<Item>
<Key />
<Value Signature="2ffb6b0d-0239-4016-b08b-40520d1687ff">
<ServiceAssignments xmlns="urn:schema:Microsoft.Rtc.Management.Settings.ServiceAssignment.2008">
<ServiceAssignment TagId="659550892">
<Component Name="Registrar">
<ServiceId xmlns="urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008" SiteId="1" RoleName="Registrar" Instance="1" />
</Component>
<Component Name="PresenceFocus">
<ServiceId xmlns="urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008" SiteId="1" RoleName="UserServices" Instance="1" />
</Component>
</ServiceAssignment>
<ServiceAssignment TagId="911048693">
<Component Name="Registrar">
<ServiceId xmlns="urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008" SiteId="1" RoleName="Registrar" Instance="2" />
</Component>
<Component Name="PresenceFocus">
<ServiceId xmlns="urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008" SiteId="1" RoleName="UserServices" Instance="2" />
</Component>
</ServiceAssignment>
</ServiceAssignments>
</Value>
</Item>
</Dictionary>
</AnchoredXml>
i try this code but give me a null exception
var MyList = doc.Root.Elements("ServiceAssignment").Select(c=>c.Attribute(("TagId")).Value).ToList();
You have namespaced elements in the document so you need to include them in your queries.
XNamespace itemNs = "urn:schema:Microsoft.Rtc.Management.ScopeFramework.2008";
XNamespace assignmentNs = "urn:schema:Microsoft.Rtc.Management.Settings.ServiceAssignment.2008";
var query =
from item in doc.Descendants(itemNs + "Item")
from assignment in item.Descendants(assignmentNs + "ServiceAssignment")
select (long)assignment.Attribute("TagId");
string xmlString =
#"<AnchoredXml xmlns='urn:schema:Microsoft.Rtc.Management.ScopeFramework.2008' SchemaWriteVersion='1'>
<Key ScopeClass='Global'>
<SchemaId Namespace='urn:schema:Microsoft.Rtc.Management.Settings.ServiceAssignment.2008' ElementName='ServiceAssignments' />
<AuthorityId Class='Host' InstanceId='00000000-0000-0000-0000-000000000000' />
</Key>
<Dictionary Count='1'>
<Item>
<Key />
<Value Signature='2ffb6b0d-0239-4016-b08b-40520d1687ff'>
<ServiceAssignments xmlns='urn:schema:Microsoft.Rtc.Management.Settings.ServiceAssignment.2008'>
<ServiceAssignment TagId='659550892'>
<Component Name='Registrar'>
<ServiceId xmlns='urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008' SiteId='1' RoleName='Registrar' Instance='1' />
</Component>
<Component Name='PresenceFocus'>
<ServiceId xmlns='urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008' SiteId='1' RoleName='UserServices' Instance='1' />
</Component>
</ServiceAssignment>
<ServiceAssignment TagId='911048693'>
<Component Name='Registrar'>
<ServiceId xmlns='urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008' SiteId='1' RoleName='Registrar' Instance='2' />
</Component>
<Component Name='PresenceFocus'>
<ServiceId xmlns='urn:schema:Microsoft.Rtc.Management.Deploy.Topology.2008' SiteId='1' RoleName='UserServices' Instance='2' />
</Component>
</ServiceAssignment>
</ServiceAssignments>
</Value>
</Item>
</Dictionary>
</AnchoredXml>";
var doc = XDocument.Parse(xmlString);
var TagIds = doc.Descendants()
.Elements()
.Where(e =>
e.HasAttributes &&
e.Name.LocalName.Equals("ServiceAssignment") &&
e.Attribute("TagId") != null)
.Select(e => e.Attribute("TagId").Value);
Your XML contains namespaces, so you can't just compare the full name.
If you don't care about the namespaces, you can use XName.LocalName:
var result = from element in doc.Root.Descendants()
where element.Name.LocalName == "ServiceAssignment"
select (int)element.Attribute("TagId");
You can try with this code
var result = from item in XElement.Load("YourFile.xml").Root.Elements("ServiceAssignment")
where item.Attribute("TagId") == value
select item ;

Categories