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();
}
}
}
Related
I am new to managing XML, I've read a couple of articles but I'm confused when it comes to a specific XML that I am working on. Can someone help me with the right statement? I just want to update the value of the ListStart, but I am getting an error when compiling. I am updating that part by this:
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.Load(#"path");
XmlNode myNode = soapEnvelopeDocument.SelectSingleNode("descendant::cet:GetListCustomElement[cet:GetListCustom/cet:ListID='101']");
soapEnvelopeDocument.LastChild.InnerText = sDate;
<soapenv:Header/>
<soapenv:Body>
<cet:GetListCustomElement>
<!--Zero or more repetitions:-->
<cet:GetListCustom>
<cet:ListID>101</cet:ListID>
<cet:ListStart>13.11.2020</cet:ListStart>
</cet:GetListCustom>
</cet:GetListCustomElement>
</soapenv:Body>
</soapenv:Envelope>```
You only supplied a piece of the xml without the namespaces. With Xml linq you can get the element without the namespaces. See code below :
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)
{
XDocument doc = XDocument.Load(FILENAME);
XElement ListStart = doc.Descendants().Where(x => x.Name.LocalName == "ListStart").FirstOrDefault();
ListStart.SetValue("14.11.2020");
}
}
}
I want to create 1095 e-file xml using c# code. For that i want to create dynamic tags that means if data is available then only creating tags otherwise it can not show that tag.
Here is sample of using xml linq to create your xml file. You can add IF statements as necessary to skip adding any elements
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 header = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><root xmlns:irs=\"myUrl\"></root>";
XDocument doc = XDocument.Parse(header);
XElement root = doc.Root;
XNamespace irs = root.GetNamespaceOfPrefix("irs");
XElement businessName = new XElement("BusinessNameLine1Txt", "Comp Name");
root.Add(businessName);
XElement tinRequest = new XElement(irs + "TINRequestTypeCd");
root.Add(tinRequest);
XElement employerEIN = new XElement(irs + "EmployerEIN", "899090900");
root.Add(employerEIN);
XElement contactNameGrp = new XElement("ContactNameGrp");
root.Add(contactNameGrp);
XElement firstName = new XElement("PersonFirstNm", "First Name Person");
contactNameGrp.Add(firstName);
XElement lastName = new XElement("PersonLastNm", "Last Name Person");
contactNameGrp.Add(lastName);
}
}
}
//sample output
//<?xml version="1.0" encoding="utf-8" ?>
//<root xmlns:irs="myUrl">
//<BusinessName>
// <BusinessNameLine1Txt>Comp Name</BusinessNameLine1Txt>
//</BusinessName>
//<irs:TINRequestTypeCd>BUSINESS_TIN</irs:TINRequestTypeCd>
//<irs:EmployerEIN>899090900</irs:EmployerEIN>
//<ContactNameGrp>
// <PersonFirstNm>First Name Person</PersonFirstNm>
// <PersonLastNm>Last Name Person</PersonLastNm>
//</ContactNameGrp> <ContactPhoneNum>9090909000</ContactPhoneNum>
//</root>
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']"
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);
}
}
}
}
}
}
Here is the XML file I need to process:
<?xml version="1.0" encoding="UTF-8"?>
<shipment-info xmlns="http://www.canadapost.ca/ws/shipment-v8">
<shipment-id>11111111</shipment-id>
<shipment-status>created</shipment-status>
<tracking-pin>123456789012</tracking-pin>
<links>
<link rel="self" href="https://xxx" media-type="application/vnd.cpc.shipment-v8+xml"/>
<link rel="details" href="https://xxx" media-type="application/vnd.cpc.shipment-v8+xml"/>
<link rel="group" href="https://xxx" media-type="application/vnd.cpc.shipment-v8+xml"/>
<link rel="price" href="https://xxx" media-type="application/vnd.cpc.shipment-v8+xml"/>
<link rel="label" href="https://xxx" media-type="application/pdf" index="0"/>
</links>
</shipment-info>
And I want to get the tracking pin value, here is the code for doing this:
// xml text
string xml = (xml source above)
// load xml
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
// getting tracking pin
XmlNode node = doc.SelectSingleNode("/shipment-info"); // problem start here -> node return null
Console.WriteLine(node["tracking-pin"].InnerText);
// getting self and label links
node = doc.SelectSingleNode("/shipment-info/links");
foreach (XmlNode child in node)
{
if (child.Attributes["rel"].Value == "self")
Console.WriteLine(child.Attributes["href"].Value);
else if (child.Attributes["rel"].Value == "label")
Console.WriteLine(child.Attributes["href"].Value);
}
Console.ReadLine();
However, for selecting "/shipment-info" it return a null value, and I don't know why this happen. How to handle it?
You have a namespace for which you need to account:
// load xml
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(doc.NameTable);
//Add the namespaces used in books.xml to the XmlNamespaceManager.
xmlnsManager.AddNamespace("veeeight", "http://www.canadapost.ca/ws/shipment-v8");
// getting tracking pin
XmlNode node = doc.SelectSingleNode("//veeeight:shipment-info", xmlnsManager); // problem start here -> node return null
see:
https://support.microsoft.com/en-us/kb/318545
You have a namespace issue. Try this XML Linq solution
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)
{
XDocument doc = XDocument.Load(FILENAME);
XNamespace ns = ((XElement)(doc.FirstNode)).Name.Namespace;
string tracking_pin = doc.Descendants(ns + "tracking-pin").FirstOrDefault().Value;
}
}
}
add that to your code
XmlNode root = doc.DocumentElement;