How to add Process Instruction to an XML file in C# - c#

How can I add a process instruction to ~50 xml files?
<?xml-stylesheet type="text/xsl" href="Sample.xsl"?>
If I append the node, it is added to the end of the file but it needs to be first.

I would use LINQ to XML:
using System;
using System.Xml.Linq;
public class Test
{
static void Main()
{
XDocument doc = XDocument.Load("test.xml");
var proc = new XProcessingInstruction
("xml-stylesheet", "type=\"text/xsl\" href=\"Sample.xsl\"");
doc.Root.AddBeforeSelf(proc);
doc.Save("test2.xml");
}
}

Related

ArgumentException: The node to be inserted is from a different document context

I've searched Stackoverflow on this question, as well as other forums but no one seems to be making this the way I'm making.
By this I mean, in my code, instead of using XMLNode, I'm using XMLElement.
So, without further ado, my intention is to save in an already existing XML Document, a new Element is a child of other existing Elements besides the root.
This is an example on my XML File:
<ROOT>
<NOT_THIS_ONE>
</NOT_THIS_ONE>
<THIS_ONE>
</THIS_ONE>
</ROOT>
So, this is my code:
//XML File
TextAsset repository = Resources.Load("Repository") as TextAsset;
//Create XML Reference
XmlDocument xmlDocument = new XmlDocument();
//Load XML File into XML Reference
xmlDocument.LoadXml(repository.text);
//Root Node
XmlNode statsNode = GetRootNode();
//Get History Node
XmlNode thisOneNode = statsNode.ChildNodes.Item(1);
The GetRootNode() function is this:
//Create Xml Reference
XmlDocument xmlData = new XmlDocument();
//Load Xml File into Xml Reference
xmlData.LoadXml(repository.text);
//Get Root Node
return xmlData.ChildNodes.Item(1);
The thisOneNode gets the <THIS_ONE> Element as a Node (at least that's what I think it does).
Later on, I do this:
XmlElement childOfThisOne = xmlDocument.CreateElement("CHILD");
XmlElement pointsSession = xmlDocument.CreateElement("POINTS");
pointsSession.InnerText = points.ToString();
childOfThisOne.AppendChild(pointsSession);
thisOneNode.AppendChild(childOfThisOne);
xmlDocument.Save("Assets/Resources/GamePoints.xml");
And my intention with this would be something like:
<ROOT>
<NOT_THIS_ONE>
</NOT_THIS_ONE>
<THIS_ONE>
<CHILD>
<POINTS>102</POINTS>
</CHILD>
</THIS_ONE>
</ROOT>
But I get the error in the title: "ArgumentException: The node to be inserted is from a different document context."
And the line in question is this: thisOneNode.AppendChild(childOfThisOne);
Now, where I've searched and the articles I found, people were using XmlNode and even used an xmlDocument.ImportNode(); I tried that too and the same error occurred. Now, I don't how to fix this and I'm requesting your help on this one.
Thank you for your time and happy holidays!
Using Xml Linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml =
#"<ROOT>
<NOT_THIS_ONE>
</NOT_THIS_ONE>
<THIS_ONE>
</THIS_ONE>
</ROOT>";
XDocument doc = XDocument.Parse(xml);
XElement thisOne = doc.Descendants("THIS_ONE").FirstOrDefault();
thisOne.Add(new XElement("CHILD", new XElement("POINTS", 102)));
doc.Save("Assets/Resources/GamePoints.xml");
}
}
}

I need to read xml file data but due to attribute it does not work

i want to read xml file but due to Document node attribute it did not read file.
Code C#:
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load(HttpContext.Server.MapPath("~/Content/Images/MMS-CREATE-ALLA-ALLAH2H1-23102018-000170-INP.xml"));
XmlNode settings = xmldoc.SelectSingleNode("Document[#xmlns='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']/MndtInitnReq/GrpHdr");
stu.BranchName = settings.SelectSingleNode("MsgId").InnerText;
XML FIle:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.009.001.01">
<MndtInitnReq>
<GrpHdr>
<MsgId>10005226074</MsgId>
<CreDtTm>2018-10-23T15:20:56</CreDtTm>
</GrpHdr>
</MndtInitnReq>
</Document>
You have a namespace that must be used to get the data. Try Xml Linq :
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication75
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace ns = doc.Root.GetDefaultNamespace();
string msgId = (string)doc.Descendants(ns + "MsgId").FirstOrDefault();
XElement xCreDtTm = doc.Descendants(ns + "CreDtTm").FirstOrDefault();
//will give 1/1/01 when null
DateTime CreDtTm = xCreDtTm == null ? new DateTime() : (DateTime)xCreDtTm;
}
}
}
I don't think loading this xml should be a problem. I verified that by loading the xml you posted in an XmlDocument object.
However I think, your xpath to get "settings" node should have xml namespace in all tags after Document.
So the xpath should be "/[local-name()='Document' and namespace-uri()='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']/[local-name()='MndtInitnReq' and namespace-uri()='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']/*[local-name()='GrpHdr' and namespace-uri()='urn:iso:std:iso:20022:tech:xsd:pain.009.001.01']"

Does XDocument.Load loads all data into memory?

I must read all first level nodes of the root node of large xml file that looks like the following:
<root>
<record n="1"><a/><b/><c/></record>
<record n="2"><a/><b/><c/></record>
<record n="3"><a/><b/><c/></record>
</root>
And my code looks like:
var xml = XDocument.Load(filename);
var firstNode = xml?.Root?.Descendants()?.FirstOrDefault();
var elements = firstNode?.Elements();
I just need to get the first child of the root and all first level descendants of it. This code works fine, but the question is: is it safe to read like this? I guess it does not load all data into memory - only the structure of the xml file?
As I see memory is not increased while debugging. It only explodes if I actually try to see what is in xml variable.
No, XDocument loads the whole document into memory. Whether it's "safe" to do this or not depends on what size of document you need to be able to handle.
If you need to handle XML files that wouldn't fit into memory, you'd want to use XmlReader, which is unfortunately considerably harder to use.
I use combination of xmlreader and xdocument. Updated code to dynamically get first tag name.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
reader.ReadStartElement(); //read root
XElement.ReadFrom(reader);// read \n
XElement record = null;
string recordName = "";
Boolean first = true;
while (!reader.EOF)
{
if (first)
{
record = (XElement)XElement.ReadFrom(reader);
first = false;
recordName = record.Name.LocalName;
}
else
{
if (reader.Name != recordName)
{
reader.ReadToFollowing(recordName);
}
if (!reader.EOF)
{
record = (XElement)XElement.ReadFrom(reader);
}
}
}
}
}
}

Fast replacement node names in XML

I use a legacy service that manage Fetch CRM: crmService.Fetch(fetchXml).
I get XML string result like this:
<resultset>
<result>
<new_categoria name="Cliente" formattedvalue="1">1</new_categoria>
<new_name>Admin</new_name>
<new_tipodecampanaid>{F8F29978-4E0F-AE92-FB43-48B4DC406B1F}</new_tipodecampanaid>
<statuscode name="Activo">0</statuscode>
</result>
<result>
<new_categoria name="Client" formattedvalue="1">1</new_categoria>
<new_name>Client</new_name>
<new_tipodecampanaid>{758341BA-4661-D694-6743-8D2DC875793E}</new_tipodecampanaid>
<statuscode name="Activo">0</statuscode>
</result>
<result>
</resultset>
We need (because alias not support for Fetch method) replace several node names:
1 - Replace new_categoria node name by org_category
2 - Replace new_name node name by org_name
3 - Replace new_tipodecampanaid node name by org_campaignid
We need high peformance, maybe results can be huge.
Using XmlDocument:
var doc = new XmlDocument();
doc.LoadXml(fetchXMLResult);
XmlNode root = doc.SelectSingleNode("resultset");
foreach (XmlNode childNode in root.ChildNodes)
{
}
Using XDocument:
XDocument resultset = XDocument.Parse(fetchXMLResult);
if (resultset.Root == null || !resultset.Root.Elements("result").Any())
{
return;
}
resultset.Root.Elements("result")
Any suggestions?
For speed you could run through the file using an XmlReader and write each node you read to a new file using an XmlWriter.
See this link for an example.
When you have large xml file always use XmlReader. Try this code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test1.xml";
const string OUTPUT_FILENAME = #"c:\temp\test2.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(INPUT_FILENAME);
XmlWriter writer = XmlWriter.Create(OUTPUT_FILENAME);
writer.WriteStartElement("resultset");
while (!reader.EOF)
{
if (reader.Name != "result")
{
reader.ReadToFollowing("result");
}
if (!reader.EOF)
{
XElement result = (XElement)XElement.ReadFrom(reader);
result.Element("new_categoria").Name = "org_category";
result.Element("new_name").Name = "org_name";
result.Element("new_tipodecampanaid").Name = "org_campaignid";
writer.WriteRaw(result.ToString());
}
}
writer.WriteEndElement();
writer.Flush();
writer.Close();
}
}
}

Create multiple XmlDocument objects based on the number of XML files in a directory

I have multiple XML files in a directory, Each directory you can consider as each scenario. Based on the business scenario number of XML files may differ in a directory.
From the Below code I got total number of files.
string tempPath = rootPath+"/Templates"; // Template directory path
DirectoryInfo d = new DirectoryInfo(#tempPath);
FileInfo[] files = d.GetFiles("*.xml"); // getting all file names
Am trying to set the namespace for the xml like the below code
//Setting namespace for each xml
foreach(FileInfo file in files)
{
var tempXml = file.Name;
XmlDocument tempXml = new XmlDocument();
tempXml.Load(tempPath+"/"+file.Name);
XmlNamespaceManager nsMgr = new XmlNamespaceManager(tempXml.NameTable);
nsMgr.AddNamespace("imp", namespace1); // namespace1 value I took it from excel
nsMgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
}
Later that I trying to insert value in the xml doc like this
XmlNode businessContactNumber = doc.SelectSingleNode(xPath,nsMgr);
The above code is not working and I know am doing some serious mistake in the code. Am new to this C# code, Kindly help me to resolve this issue.
Using XML Linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication62
{
class Program
{
const string FOLDER = #"\c:\temp";
static void Main(string[] args)
{
string[] filenames = Directory.GetFiles(FOLDER);
foreach (string file in filenames)
{
XDocument tempXml = XDocument.Load(file);
XElement root = (XElement)tempXml.FirstNode;
XNamespace nsMgr = root.Name.Namespace;
XElement node = root.Descendants(nsMgr + "TagName").FirstOrDefault();
}
}
}
}

Categories

Resources