Can anybody tell me why navigating xml with an instruction fails :
StringBuilder sb2 = new System.Text.StringBuilder();
XmlDocument doc = new XmlDocument( );
// --- XML without instruction -> Parsing succeeds
sb1.AppendLine( #"<MetalQuote>");
sb1.AppendLine( #"<Outcome>Success</Outcome>");
sb1.AppendLine( #"<Ask>1073.3</Ask>");
sb1.AppendLine( #"</MetalQuote>");
doc.LoadXml( sb1.ToString( ));
System.Diagnostics.Debug.WriteLine( doc.SelectSingleNode( "//MetalQuote/Outcome").InnerText);
This works well, but the same XML with an instruction fails :
// --- XML with instruction -> Parsing fails
sb2.AppendLine( #"<MetalQuote xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.xignite.com/services"" >");
sb2.AppendLine( #"<Outcome>Success</Outcome>");
sb2.AppendLine( #"<Ask>1073.3</Ask>");
sb2.AppendLine( #"</MetalQuote>");
doc.LoadXml( sb2.ToString( ));
System.Diagnostics.Debug.WriteLine( doc.SelectSingleNode( "//MetalQuote/Outcome").InnerText);
I get an exception at the doc.SelectSingleNode statement.
In your version with instructions you are using a custom namespace. Each node will inherit that and you have to take it into account when requesting the node data. One way to do it is to use XmlNamespaceManager. Below a version of your code that applies the manager:
class Program
{
static void Main(string[] args)
{
StringBuilder sb2 = new System.Text.StringBuilder();
XmlDocument doc = new XmlDocument();
// --- XML with instruction -> Parsing fails
sb2.AppendLine(#"<MetalQuote xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.xignite.com/services"" >");
sb2.AppendLine(#"<Outcome>Success</Outcome>");
sb2.AppendLine(#"<Ask>1073.3</Ask>");
sb2.AppendLine(#"</MetalQuote>");
doc.LoadXml(sb2.ToString());
// Create a manager
XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
xnm.AddNamespace("abc", #"http://www.xignite.com/services");
// Use the namespace for each node
System.Diagnostics.Debug
.WriteLine(doc.SelectSingleNode(#"//abc:MetalQuote/abc:Outcome", xnm).InnerText);
}
}
There other options available as well. Check this blog post for more details.
Here are two ways with 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)
{
StringBuilder sb2 = new System.Text.StringBuilder();
sb2.AppendLine(#"<MetalQuote xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""http://www.xignite.com/services"" >");
sb2.AppendLine(#"<Outcome>Success</Outcome>");
sb2.AppendLine(#"<Ask>1073.3</Ask>");
sb2.AppendLine(#"</MetalQuote>");
XDocument doc = XDocument.Parse(sb2.ToString());
XElement outCome = doc.Descendants().Where(x => x.Name.LocalName == "Outcome").FirstOrDefault();
XElement metalQuote = (XElement)doc.FirstNode;
XNamespace ns = metalQuote.Name.Namespace;
XElement outCome2 = doc.Descendants(ns + "Outcome").FirstOrDefault();
}
}
}
Related
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 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();
}
}
}
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;
In my case I want to add multiple root nodes to the given xml schema. So I have to append the different user elements with it's child nodes in multiple times by appending with the previous contents in the xml file. My problem is how can I add multiple root elements? (I could add one root element but no idea how to add next ).
This is the xml schema
<?xml version="1.0" encoding="utf-8"?>
<SessionId>
<Scource>
<User username="AB">
<DOB>25/5/1980</DOB>
<FirstName>AVS</FirstName>
<LastName>WDW</LastName>
<Location>FWAWE</Location>
</User>
<User username="AqB">
<DOB>25/5/1980</DOB>
<FirstName>AVS</FirstName>
<LastName>WDW</LastName>
<Location>FWAWE</Location>
</User>
</Scource>
</SessionId>
This is my C# code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace FilteringNightwing
{
class Test
{
static void Main(string[] args) {
string fileLocation = "clients.xml";
if (!File.Exists(fileLocation))
{
XmlTextWriter writer = new XmlTextWriter(fileLocation, null);
writer.WriteStartElement("SessionId");
writer.WriteEndElement();
writer.Close();
}
// Load existing clients and add new
XElement xml = XElement.Load(fileLocation);
xml.Add(new XElement("User",
new XAttribute("username", "AqB"),
new XElement("DOB", "25/5/1980"),
new XElement("FirstName", "AVS"),
new XElement("LastName", "WDW"),
new XElement("Location", "FWAWE")));
xml.Save(fileLocation);
}
}
}
How can I add "Source" tag as another root element. All your answers are welcome.
You can't have more than one root node. Parsing the following will give you an error.
XElement root = XElement.Parse("<a></a><b></b>");
This will error too:
XElement root = XElement.Parse("<a></a><a></a>");
If you want multiple children nodes to the root node, that is perfectly fine. You can have nodes with the same name or different. Such as:
<a>
<b />
<c>
<d />
</c>
<b />
</a>
Add new user to Scource:
XElement xml = XElement.Load(fileLocation);
XElement scource = xml.Element("Scource"); // Find Scource here
scource.Add(new XElement("User", // Add new user to Scource here
new XAttribute("username", "AqB"),
new XElement("DOB", "25/5/1980"),
new XElement("FirstName", "AVS"),
new XElement("LastName", "WDW"),
new XElement("Location", "FWAWE")));
xml.Save(fileLocation);
Try this
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 = "<?xml version=\"1.0\" encoding=\"utf-8\"?><SessionId><Source></Source></SessionId>";
XDocument doc = XDocument.Parse(xml);
XElement source = doc.Descendants("Source").FirstOrDefault();
source.Add(new XElement("User", new object[] {
new XAttribute("username", "AqB"),
new XElement("DOB", "25/5/1980"),
new XElement("FirstName", "AVS"),
new XElement("LastName", "WDW"),
new XElement("Location", "FWAWE")
}));
}
}
}