Adding an XMLNode below a specific node - c#

Here is my XML structure
<?xml version="1.0" encoding="utf-8"?>
<Projects xmlns="urn:projects-schema">
<Project>
<Name>Project1</Name>
<Images>
<Image Path="D:/abc.jpg"></Image>
</Images>
</Project>
</Projects>
I want to be able to Add a new Project Node though my code
And I want to be able to Create a new Image Node given a the Project Name
For the first task I have this so far:
try
{
var filename = Server.MapPath("~/App_Data/Projects.xml");
var doc = new XmlDocument();
if (System.IO.File.Exists(filename))
{
if (!ProjectExists(projectName))
{
doc.Load(filename);
var root = doc.DocumentElement;
var newElement = doc.CreateElement("Project");
root.AppendChild(newElement);
root = doc.DocumentElement;
newElement = doc.CreateElement("Name");
var textNode = doc.CreateTextNode(projectName);
root.LastChild.AppendChild(newElement);
root.LastChild.LastChild.AppendChild(textNode);
doc.Save(filename);
}
else
throw new ApplicationException("Project already exists");
doc = null;
}
}
catch (Exception ex)
{
throw ex;
}
But I am struggling for the second part. This is what I have so far:
if (System.IO.File.Exists(projectFilename))
{
doc.Load(projectFilename);
XmlNode root = doc.DocumentElement;
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("prj", "urn:projects-schema");
root = root.SelectSingleNode("descendant::prj:Project[prj:Name='" + projectName + "']", nsManager);
}
Any help will be appreciated. Thanks

XElement projects = XElement.Parse (
#"<Projects xmlns='urn:projects-schema'>
<Project>
<Name>Project1</Name>
<Images>
<Image Path='D:/abc.jpg'></Image>
</Images>
</Project>
</Projects>");
For Task 1, this can be done as follows:
projects.LastNode.AddAfterSelf(new XElement("Project",
new XElement("Name", "Project2"),
new XElement("Images",
new XElement("Image", "", new XAttribute("Path", "C:/abc.jpg"))
)));
Task 2:
projects.Descendants("Name")
.Where(x => x.Value == projectName).FirstOrDefault()
.AddAfterSelf(new XElement("Images",
new XElement("Image", "", new XAttribute("Path", "C:/def.jpg"))
)
);
EDIT: To check if an Images element exists and add a child Image element with an attribute to it
projects.Descendants("Project")
.Where(x => x.Elements("Images").Any())
.Descendants("Images").FirstOrDefault()
.Add(new XElement("Image", "", new XAttribute("Path", "D:/xyz.jpg")));

Related

Can not create XML in one method and then append child nodes in another method

I have following code I want to use:
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
WriteXmlFile("PartNew", doc);
}
public static void WriteXmlFile(string nextItem, XmlDocument doc)
{
XmlElement root = doc.DocumentElement;
XmlElement id = doc.CreateElement(nextItem);
id.SetAttribute("Part", nextItem);
doc.DocumentElement.AppendChild(id);
root.AppendChild(id);
}
The problem is that I am getting an error message saying that my DocumentElement is null. This is the line where I get the error message doc.DocumentElement.AppendChild(id);. I googled but I didn't find any similar case I have. What do I miss to get my code running?
Error message:
NullReferenceException on object DocumentElement
You do not create a root element.
XmlDocument doc = new XmlDocument();
XmlNode rootNode = doc.CreateElement("root");
doc.AppendChild(rootNode);
Instead of using XmlDocument and all those manipulations with adding XML declarations, you could use LINQ-aware XDocument:
var xml = new XDocument(
new XDeclaration("1.0","utf-8", "yes"),
new XElement("root",
new XElement("PartNew", new XAttribute("Part", "1"))));
Console.WriteLine(xml.Declaration.ToString() + "\n" + xml.ToString());
Output:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
<PartNew Part="1" />
</root>
You can apply LINQ to create elements:
var xml2 = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("root",
from x in new[] {1, 2, 3}
select new XElement("PartNew", new XAttribute("Part", x))));
Console.WriteLine(xml2.Declaration.ToString() + "\n" + xml2.ToString());
Output:
<root>
<PartNew Part="1" />
<PartNew Part="2" />
<PartNew Part="3" />
</root>

XElement with LINQ add node after specific node

I've got this XML:
<?xml version="1.0" encoding="utf-8"?>
<JMF SenderID="InkZone-Controller" Version="1.2">
<Command ID="cmd.00695" Type="Resource">
<ResourceCmdParams ResourceName="InkZoneProfile" JobID="K_41">
<InkZoneProfile ID="r0013" Class="Parameter" Locked="false" Status="Available" PartIDKeys="SignatureName SheetName Side Separation" DescriptiveName="Schieberwerte von DI" ZoneWidth="32">
<InkZoneProfile SignatureName="SIG1">
<InkZoneProfile Locked="False" SheetName="S1">
<InkZoneProfile Side="Front">
<ColorPool Class="Parameter" DescriptiveName="Colors for the job" Status="Available">
<InkZoneProfile Separation="PANTONE 647 C" ZoneSettingsX="0 0,003 " />
</ColorPool>
</InkZoneProfile>
</InkZoneProfile>
</InkZoneProfile>
</InkZoneProfile>
</ResourceCmdParams>
</Command>
</JMF>
I'm trying to add a node after a specific node() , using XElement and Linq. But my LINQ query always returns me null.
Tried this:
XElement InkZonePath = XmlDoc.Element("JMF").Elements("InkZoneProfile").Where(z => z.Element("InkZoneProfile").Attribute("Side").Value == "Front").SingleOrDefault();
And this:
XmlDoc.Element("JMF")
.Elements("InkZoneProfile").Where(InkZoneProfile => InkZoneProfile.Attribute("Side")
.Value == "Front").FirstOrDefault().AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", x.colorname),
new XAttribute("ZoneSettingsX", x.colorvalues)));
I've built this queries following those examples:
Select XElement where child element has a value
Insert XElements after a specific node
LINQ-to-XML XElement query NULL
But it didn't worked as expected. What is wrong with the LINQ Query ? From what i've read it should work (logically reading the expression i can understand it).
Thanks
EDIT-1: Entire writexml Method
public void writexml(xmldatalist XMLList, variables GlobalVars)
{
XmlWriterSettings settings = new XmlWriterSettings
{
Indent = true,
IndentChars = "\t",
NewLineChars = Environment.NewLine,
NewLineHandling = NewLineHandling.Replace,
Encoding = new UTF8Encoding(false)
};
string DesktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
string FileExtension = ".xml";
string PathString = Path.Combine(DesktopFolder, "XML");
System.IO.Directory.CreateDirectory(PathString);
foreach (List<xmldata> i in XMLList.XMLArrayList)
{
int m = 0;
foreach (var x in i)
{
string XMLFilename = System.IO.Path.GetFileNameWithoutExtension(x.xml_filename);
GlobalVars.FullPath = Path.Combine(PathString, XMLFilename + FileExtension);
if (!File.Exists(GlobalVars.FullPath))
{
XDocument doc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("JMF",
new XAttribute("SenderID", "InkZone-Controller"),
new XAttribute("Version", "1.2"),
new XElement("Command",
new XAttribute("ID", "cmd.00695"),
new XAttribute("Type", "Resource"),
new XElement("ResourceCmdParams",
new XAttribute("ResourceName", "InkZoneProfile"),
new XAttribute("JobID", "K_41"),
new XElement("InkZoneProfile",
new XAttribute("ID", "r0013"),
new XAttribute("Class", "Parameter"),
new XAttribute("Locked", "False"),
new XAttribute("Status", "Available"),
new XAttribute("PartIDKeys", "SignatureName SheetName Side Separation"),
new XAttribute("DescriptiveName", "Schieberwerte von DI"),
new XAttribute("ZoneWidth", "32"),
new XElement("InkZoneProfile",
new XAttribute("SignatureName", "SIG1"),
new XElement("InkZoneProfile",
new XAttribute("Locked", "false"),
new XAttribute("SheetName", "S1"),
new XElement("InkZoneProfile",
new XAttribute("Side", "Front"),
new XElement("ColorPoolClass",
new XAttribute("Class", "Parameter"),
new XAttribute("DescriptiveName", "Colors for the job"),
new XAttribute("Status", "Available")
)))))))));
doc.Save(GlobalVars.FullPath);
XDocument XmlDoc = new XDocument();
XmlDoc = XDocument.Load(GlobalVars.FullPath);
XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();
if (InkZonePath != null)
{
InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", x.colorname),
new XAttribute("ZoneSettingsX", x.colorvalues)));
}
XmlDoc.Save(GlobalVars.FullPath);
}//Closing !FileExists
}//Closing inner foreach
}//Closing outer foreach
}//Closing writexml method
The problem with your current code is here : Element("JMF").Elements("InkZoneProfile") Since InkZoneProfile is not a direct child of JMF it will not return anything. Use Descendants instead.
Check difference between Elements & Descendants.
This should give you correct result:-
XElement InkZonePath = xdoc.Element("JMF").Descendants("InkZoneProfile")
.SingleOrDefault(z => (string)z.Attribute("Side") == "Front")
After this you can add whatever node you want to add using AddAfterSelf. Also note I have used SingleOrDefault here, but you may get exception if you have multiple matching nodes with this, In that case consider using FirstOrDefault.
Update:
To add new node:-
if (InkZonePath != null)
{
InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", "Test"),
new XAttribute("ZoneSettingsX", "Test2")));
}
//Save XDocument
xdoc.Save(#"C:\Foo.xml");
You need to use Descendants method instead Elements:
XElement InkZonePath = XmlDoc.Root.Descendants("InkZoneProfile").Where(z => (string)z.Attribute("Side") == "Front").SingleOrDefault();
if(InkZonePath !=null)
InkZonePath.AddAfterSelf(new XElement("InkZoneProfile",
new XAttribute("Separation", x.colorname),
new XAttribute("ZoneSettingsX", x.colorvalues)));
you can use Descendants instead.
var node = XmlDoc.Descendants("InkZoneProfile").Where(x=> x.Attribute("Side") !=null && x.Attribute("Side").Value == "Front").FirstorDefault();

How to add elements in an XML file?

How should I add X there in XElement ?
XDocument triggerDocument = new XDocument(
new XDeclaration("1.0", "utf-8", null));
XElement triggerRoot = new XElement("config",
new XElement("maketool-config",
new XElement("hmi", new XElement("Messages",X))));
triggerDocument.Add(triggerRoot);
triggerDocument.Save(Path.Combine(outPath, "_triggers.xml"));
for (int i = 0; i <= events.Count; i++)
{
foreach (var item in events)
{
triggerRoot.Add(new XElement("n",
new XAttribute("page", item.page),
new XAttribute("sequence", item.sequence),
new XAttribute("priority", item.priority),
new XAttribute("errorText", item.errorText)
));
}
}
so it should look like this :
<?xml version="1.0" encoding="utf-8"?>
<config schema ="sdk-hmi.xsd">
<maketool-config>
<hmi>
<messages>
<n page="" sequence="" priority="" errorText="" />
<n page="" sequence="" priority="" errorText="" />
<n page="" sequence="" priority="" errorText="" />
<n page="" sequence="" priority="" errorText="" />
<n page="" sequence="" priority="" errorText="" />
</messages>
</hmi>
</maketool-config>
</config>
You can pass an XElement[] or IEnumerable<XElement> to XElement's constructor:
var messages = events.Select(item => new XElement("n",
new XAttribute("page", item.page),
new XAttribute("sequence", item.sequence),
new XAttribute("priority", item.priority),
new XAttribute("errorText", item.errorText)
));
XDocument triggerDocument = new XDocument(
new XDeclaration("1.0", "utf-8", null));
XElement triggerRoot = new XElement("config",
new XElement("maketool-config",
new XElement("hmi",
new XElement("Messages", messages))) // <<<--- This is the important part.
);
triggerDocument.Add(triggerRoot);
You can try this:
XDocument triggerDocument = new XDocument(
new XDeclaration("1.0", "utf-8", null));
XElement triggerRoot = new XElement("config",
new XElement("maketool-config",
new XElement("hmi", new XElement("Messages"))));
triggerDocument.Add(triggerRoot);
XElement msgNode = triggerRoot.Elements("Messages")
.SingleOrDefault();
if (msgNode != null)
{
foreach (var item in events)
{
msgNode.Add(new XElement("n",
new XAttribute("page", item.page),
new XAttribute("sequence", item.sequence),
new XAttribute("priority", item.priority),
new XAttribute("errorText", item.errorText)
));
}
}
May this will help to add nodes...
//file name
string filename = #"d:\temp\XMLFile2.xml";
//create new instance of XmlDocument
XmlDocument doc = new XmlDocument();
//load from file
doc.Load(filename);
//create node and add value
XmlNode node = doc.CreateNode(XmlNodeType.Element, "Genre_Genre_Country", null);
node.InnerText = "this is new node";
//add to elements collection
doc.DocumentElement.AppendChild(node);
//save back
doc.Save(filename);

Creating XMLDocument throguh code in asp.net

am trying to generate an XML document like this through code.
<TestRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://localhost:2292/RMSchema.xsd">
<Version>3</Version>
<ApplicationHeader>
<AppLanguage />
<UserId>rmservice</UserId>
</ApplicationHeader>
<CustomerData>
<ExistingCustomerData>
<MTN>2084127182</MTN>
</ExistingCustomerData>
</CustomerData>
</TestRequest>
I tried some samples. But they create xmlns for the children, which i dont need. Any help is really appreciated.
I have tried the below code. But it is adding only xmlns to all children, which i dont need
XmlDocument xDocument = new XmlDocument();
xDocument.AppendChild(xDocument.CreateXmlDeclaration("1.0", "windows-1252", null));
XmlElement xRoot = xDocument.CreateElement("TestRequest", "XNamespace.Xmlns=http://www.w3.org/2001/XMLSchema-instance" + " xsi:noNamespaceSchemaLocation=" + "http://localhost:2292/RMSchema.xsd");
xDocument.AppendChild(xRoot);
xRoot.AppendChild(xDocument.CreateElement("Version")).InnerText = 1;
Thanks
Tutu
I have tried with
var xsi = "http://www.w3.org/2001/XMLSchema-instance";
XmlElement xRoot = xDocument.CreateElement("xsi","RMRequest",xsi);
xRoot.SetAttribute("noNamespaceSchemaLocation", xsi, "http://localhost:2292/RMSchema.xsd");
xDocument.AppendChild(xRoot);
Now the response is
<?xml version=\"1.0\" encoding=\"windows-1252\"?><xsi:TestRequest xsi:noNamespaceSchemaLocation=\"http://localhost:2292/RMSchema.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">
Here is the awesome LINQ to XML. Enjoy!
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XDocument doc = new XDocument(new XDeclaration("1.0", "windows-1252", null),
new XElement("TestRequest",
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
new XAttribute(xsi + "noNamespaceSchemaLocation", "http://localhost:2292/RMSchema.xsd"),
new XElement("Version",
new XText("3")
),
new XElement("ApplicationHeader",
new XElement("AppLanguage"),
new XElement("UserId",
new XText("rmservice")
)
),
new XElement("CustomerData",
new XElement("ExistingCustomerData",
new XElement("MTN",
new XText("2084127182")
)
)
)
)
);
doc.Save(filePath);
If you really want the old API, here it is:
var xDocument = new XmlDocument();
xDocument.AppendChild(xDocument.CreateXmlDeclaration("1.0", "windows-1252", null));
var xsi = "http://www.w3.org/2001/XMLSchema-instance";
var xRoot = xDocument.CreateElement("TestRequest");
var attr = xDocument.CreateAttribute("xsi", "noNamespaceSchemaLocation", xsi);
attr.Value = "http://localhost:2292/RMSchema.xsd";
xRoot.Attributes.Append(attr);
xRoot.AppendChild(xDocument.CreateElement("Version")).InnerText = "1";
// .. your other elemets ...
xDocument.AppendChild(xRoot);
xDocument.Save(filePath);
EDIT: From your comments, it looks like you want the xmlns:xsi and other attribute in that specific order. If so, you may have to trick the XmlDocument to add the xmlns:xsi attribute first.
var xDocument = new XmlDocument();
xDocument.AppendChild(xDocument.CreateXmlDeclaration("1.0", "windows-1252", null));
var xsi = "http://www.w3.org/2001/XMLSchema-instance";
var xRoot = xDocument.CreateElement("TestRequest");
// add namespace decl are attribute
var attr = xDocument.CreateAttribute("xmlns:xsi");
attr.Value = xsi;
xRoot.Attributes.Append(attr);
// no need to specify prefix, XmlDocument will figure it now
attr = xDocument.CreateAttribute("noNamespaceSchemaLocation", xsi);
attr.Value = "http://localhost:2292/RMSchema.xsd";
xRoot.Attributes.Append(attr);
xRoot.AppendChild(xDocument.CreateElement("Version")).InnerText = "1";
// .. your other elemets ...
xDocument.AppendChild(xRoot);
xDocument.Save(filePath);
Are you looking for something like this:-
XmlDocument xmldoc = new XmlDocument();
XmlNode root = xmldoc.AppendChild(xmldoc.CreateElement("Root"));
XmlNode child = root.AppendChild(xmldoc.CreateElement("Child"));
XmlAttribute childAtt =child.Attributes.Append(xmldoc.CreateAttribute("Attribute"));
childAtt.InnerText = "My innertext";
child.InnerText = "My node Innertext";
xmldoc.Save("ABC.xml");

How to insert xml data into existing xml in c#?

i added xml file in my windows application, i want to add values to that from textbox..
i used the following code,
string path = "codedata.xml";
XmlDocument doc = new XmlDocument();
if (!System.IO.File.Exists(path))
{
//Create neccessary nodes
XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
XmlComment comment = doc.CreateComment("This is an XML Generated File");
doc.AppendChild(declaration);
doc.AppendChild(comment);
}
else //If there is already a file
{
// //Load the XML File
doc.Load(path);
}
//Get the root element
XmlElement root = doc.DocumentElement;
XmlElement Subroot = doc.CreateElement("data");
XmlElement Companycode = doc.CreateElement("Companycode");
XmlElement Productcode = doc.CreateElement("Productcode");
XmlElement Productname = doc.CreateElement("Productname");
XmlElement Brandcode = doc.CreateElement("Brandcode");
XmlElement Brandname = doc.CreateElement("Brandname");
Companycode.InnerText = txt_companycode.Text;
Productcode.InnerText = txt_productcode.Text;
Productname.InnerText = txt_productname.Text;
Brandcode.InnerText = txt_brandcode.Text;
Brandname.InnerText = txt_brandname.Text;
Subroot.AppendChild(Companycode);
Subroot.AppendChild(Productcode);
Subroot.AppendChild(Productname);
Subroot.AppendChild(Brandcode);
Subroot.AppendChild(Brandname);
root.AppendChild(Subroot);
doc.AppendChild(root);
//Save the document
doc.Save(path);
//Show confirmation message
MessageBox.Show("Details added Successfully");
it showing error near root.AppendChild(Subroot); can any one help me, wer i made mistake.
You can use Linq to XML, here is an example :
var xDoc = XElement.Load("FilePath");
if (xDoc == null)
return;
var myNewElement = new XElement("ElementName"
new XAttribute("AttributeName", value1),
new XAttribute("AttributeName", value2)
//And so on ...
);
xDoc.Add(myNewElement);
xDoc.Save("FilePath");
The root is null. Try to add Root element when you create XML file.
if (!System.IO.File.Exists(path))
{
//Create neccessary nodes
XmlDeclaration declaration = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
XmlComment comment = doc.CreateComment("This is an XML Generated File");
doc.AppendChild(declaration);
doc.AppendChild(comment);
doc.AppendChild(doc.CreateElement("Root"));
}
Or use LINQ-XML
string _file=#"c:\sample.xml";
XDocument doc;
if (!File.Exists(_file))
{
doc = new XDocument();
doc.Add(new XElement("Root"));
}
else
{
doc = XDocument.Load(_file);
}
doc.Root.Add(
new XElement("data",
new XElement("CompanyCode","C101"),
new XElement("ProductCode","P101")
)
);
doc.Save(_file);
In null XML DocumentElement is null. Try add Subroot to Document:
XmlElement root = doc.DocumentElement;
root.AppendChild(Subroot);
doc.AppendChild(root);
// new code
doc.AppendChild(Subroot);

Categories

Resources