Read XML NodeList - c#

I am trying to parse an XML response from a REST call. I can read the XML just fine with my stream reader but when I try to select the first node, it brings back nothing. Here is my XML:
<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<slot_meta_data xmlns:ns2="http://www.w3.org/2005/Atom">
<product id="MDP">
<name>MDP</name>
</product>
<product id="CTxP">
<name>CTxP</name>
</product>
<product id="STR">
<name>STR</name>
</product>
<product id="ApP">
<name>ApP</name>
<slot>
<agent_id>-1111</agent_id>
<agent_name>ApP</agent_name>
<index_id>-1</index_id>
<alias>App Alias</slot_alias>
</slot>
</product>
<product id="TxP">
<name>TxP</name>
<slot>
<agent_id>2222</agent_id>
<agent_name>App2</agent_name>
<index_id>-1</index_id>
<alias>App2 Alias</slot_alias>
</slot>
</product>
</slot_meta_data>
Here is my code
string newURL = "RESTURL";
HttpWebRequest request = WebRequest.Create(newURL) as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
StreamReader reader = new StreamReader(response.GetResponseStream());
XmlDocument xdoc = new XmlDocument();
xdoc.Load(response.GetResponseStream());
XmlNodeList list = xdoc.SelectNodes("/slot_meta_data[#*]");
foreach (XmlNode node in list)
{
XmlNode product = node.SelectSingleNode("product");
string name = product["name"].InnerText;
string id = product["id"].InnerText;
Console.WriteLine(name);
Console.WriteLine(id);
Console.ReadLine();
}
When I debug list, it has a count of 0.

Using xml linq
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication22
{
class Program
{
const string FILENAME = #"c:\TEMP\TEST.XML";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
var results = doc.Descendants("product").Select(x => new {
name = (string)x.Element("name"),
slot = x.Elements("slot").Select(y => new {
agent_id = (int)y.Element("agent_id"),
agent_name = (string)y.Element("agent_name"),
index_id = (int)y.Element("index_id"),
slot_alias = (string)y.Element("slot_alias")
}).FirstOrDefault()
}).ToList();
}
}
}

Related

get specific node from XML using XDOCUMENT

I have an XML document with ISO-8859-1 encoding.
I can load the XML with XDOCUMENT, but i can't storage a specific node.
Can somebody help me with this?
The xml:
<?xml version="1.0" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<TERMEKADATOutput xmlns="http://xmlns.oracle.com/orawsv/PUPHAX/PUPHAXWS">
<RETURN>
<OBJTERMEKADAT>
<TTT>210037069</TTT>
<TK>OGYI-T-04617/05</TK>
</OBJTERMEKADAT>
</RETURN>
</TERMEKADATOutput>
</soap:Body>
</soap:Envelope>
And the code:
XDocument xmlDoc = null;
using (StreamReader oReader = new StreamReader(#"C:\Users\maruzsama\source\repos\EPPuphax\EPPuphax\asd.xml", Encoding.GetEncoding("ISO-8859-1")))
{
xmlDoc = XDocument.Load(oReader); //this working fine
var result = from q in xmlDoc.Descendants("OBJTERMEKADAT")
select new
{
asd = q.Element("TTT").Value
};
Console.ReadKey();
}
I need the data from the TTT node (210037069)
Try following changes :
XDocument xmlDoc = null;
using (StreamReader oReader = new StreamReader(#"C:\Users\maruzsama\source\repos\EPPuphax\EPPuphax\asd.xml", Encoding.GetEncoding("ISO-8859-1")))
{
xmlDoc = XDocument.Load(oReader); //this working fine
XElement TERMEKADATOutput = xmlDoc.Descendants().Where(x => x.Name.LocalName == "TERMEKADATOutput").First();
XNamespace ns = TERMEKADATOutput.GetDefaultNamespace();
var result = from q in TERMEKADATOutput.Descendants(ns + "OBJTERMEKADAT")
select new
{
asd = q.Element(ns + "TTT").Value
};
Console.ReadKey();
}

Unable to use LINQ to XML to loop through xml document

I'm trying to get the element values of the following XML document using LINQ but I'm getting "Object reference not set to an instance of an object.";
XML:
<soapenv:Envelope xmlns:soapenv=http://schemas.xmlsoap.org/soap/envelope/
xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance>
<soapenv:Body>
<ns1:GetContactResponse soapenv:encodingStyle=http://schemas.xmlsoap.org/soap/encoding/ xmlns:ns1=http://DefaultNamespace>
<GetContactReturn xsi:type="ns2:Response" xmlns:ns2=http://getContact.contact.V300>
<Contact xsi:type="ns3:Contact" xmlns:ns3=http://_contact.contact.V300>
<Address xsi:type="xsd:string">123 test</Address>
<Address2 xsi:type="xsd:string"/>
<City xsi:type="xsd:string">Los Angeles</City>
<CountryCode xsi:type="xsd:string">US</CountryCode>
<StateCode xsi:type="xsd:string">CA</StateCode>
<ZipCode xsi:type="xsd:string">90001</ZipCode>
</Contact>
<Errors soapenc:arrayType="ns4:Error[0]" xsi:type="soapenc:Array" xmlns:ns4=http://response.base.V300 xmlns:soapenc=http://schemas.xmlsoap.org/soap/encoding//>
<IsSuccessful xsi:type="xsd:boolean">true</IsSuccessful>
<RecordCount xsi:type="xsd:double">1.0</RecordCount>
</GetContactReturn>
</ns1:GetContactResponse>
</soapenv:Body>
</soapenv:Envelope>
I'm using the following to loop through:
using (StreamReader rd = new StreamReader(services.GetResponseStream()))
{
var ServiceResult = rd.ReadToEnd();
XDocument xdoc = new XDocument();
xdoc = XDocument.Parse(ServiceResult);
var xDocResult = (from x in xdoc.Descendants("Contacts")
select new Location
{
Address = x.Element("Address").Value,
Address2 = x.Element("Address2").Value,
city = x.Element("City").Value,
statecode = x.Element("StateCode").Value,
zipcode = x.Element("ZipCode").Value
});
}
I'm assuming it's because there is no root. How do I get the values of the individual elements?
Your xml has lots of errors. I'm using StringReader. You should replace with StreamReader. Here is correction
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns1:GetContactResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://DefaultNamespace">
<GetContactReturn xsi:type="ns2:Response" xmlns:ns2="http://getContact.contact.V300">
<Contact xsi:type="ns3:Contact" xmlns:ns3="http://_contact.contact.V300">
<Address xsi:type="xsd:string">123 test</Address>
<Address2 xsi:type="xsd:string"/>
<City xsi:type="xsd:string">Los Angeles</City>
<CountryCode xsi:type="xsd:string">US</CountryCode>
<StateCode xsi:type="xsd:string">CA</StateCode>
<ZipCode xsi:type="xsd:string">90001</ZipCode>
</Contact>
<Errors soapenv:arrayType="ns4:Error[0]" xsi:type="soapenc:Array" xmlns:ns4="http://response.base.V300 xmlns:soapenc=http://schemas.xmlsoap.org/soap/encoding"/>
<IsSuccessful xsi:type="xsd:boolean">true</IsSuccessful>
<RecordCount xsi:type="xsd:double">1.0</RecordCount>
</GetContactReturn>
</ns1:GetContactResponse>
</soapenv:Body>
</soapenv:Envelope>
Here is the c# code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringReader reader = new StringReader(xml);
XDocument doc = XDocument.Load(reader);
XElement contact = doc.Descendants().Where(x => x.Name.LocalName == "Contact").FirstOrDefault();
XNamespace ns = contact.GetDefaultNamespace();
string address = (string)contact.Element(ns + "Address");
string address2 = (string)contact.Element(ns + "Address2");
string city = (string)contact.Element(ns + "City");
string country = (string)contact.Element(ns + "CountryCode");
string state = (string)contact.Element(ns + "StateCode");
string zip = (string)contact.Element(ns + "ZipCode");
}
}
}

How can I iterate through xml and remove the duplicates? C#

I've created a program to retrieve data from a database and convert it to XML. It returns a list of 24 objects that I created:
<?xml version = "1.0" encoding = "utf-16"
<ArrayOfData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Data>
<interval>01</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-10</amount>
</Data>
<Data>
<interval>02</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-11</amount>
</Data>
<Data>
<interval>03</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-12</amount>
</Data>
<Data>
<interval>04</interval>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<amount>-13</amount>
</Data>
Basically the data goes on with incrementing intervals by 1 up to 24.
What I am looking for is to look for what is duplicate and just concatenate them into one child, and then to look for what differs and create a different element for it but keep them everything in one child. How can I write the XML to do this? Example:
<Data>
<num>12345</num>
<id>ABC123 </id>
<type>LETTER</type>
<party>1</party>
<details>
<interval>01</interval>
<amount>-10</amount>
</details>
<details>
<interval>02</interval>
<amount>-11</amount>
</details>
<details>
<interval>03</interval>
<amount>-12</amount>
</details>
<details>
<interval>04</interval>
<amount>-13</amount>
</details>
</Data>
I want to create a function that returns this XML. The parameters in my current function now are just there to get the data using those parameters. Here's how I generate the XML now:
public IActionResult CreateXML(int num, int id)
{
string xml = "";
var temp = (from x in Context.InternalData.AsNoTracking() where (x.num == num && x.id == id) select x).ToList();
using (var stringwrite = new Utf8StringWriter())
{
var serializer = new XmlSerializer(temp.GetType());
serializer.Serialize(stringwrite, temp);
xml = stringwrite.ToString();
StringReader reader = new StringReader(stringwriter.ToString());
reader.ReadLine(); //skips the UTF-16 header
XDocument doc = XDocument.Load(reader);
XElement arrayOfData = doc.Root;
List<XElement> newData = new List<XElement>();
var parties = doc.Descendants("Data")
.GroupBy(x => (string)x.Element("id"))
.ToList();
foreach (var party in parties)
{
XElement template = party.First();
List<XElement> details = party.Select(x => new XElement("details", new object[] {
new XElement("interval", (string)x.Element("interval")),
new XElement("amount", (string)x.Element("amount"))
})).ToList();
template.Element("interval").Remove();
template.Element("amount").Remove();
template.Add(details);
newData.Add(template);
}
arrayOfData.ReplaceAll(newData);
return Ok(arrayOfData);
}
}
I am new to this and have never worked with generating XML before. Any help would be greatly appreciated!
Try 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 ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string xml = File.ReadAllText(FILENAME);
StringWriter stringwriter = new StringWriter();
stringwriter.Write(xml);
StringReader reader = new StringReader(stringwriter.ToString());
reader.ReadLine(); //skips the UTF-16 header
XDocument doc = XDocument.Load(reader);
XElement arrayOfData = doc.Root;
List<XElement> newData = new List<XElement>();
var parties = doc.Descendants("Data")
.GroupBy(x => (string)x.Element("id"))
.ToList();
foreach (var party in parties)
{
XElement template = party.First();
List<XElement> details = party.Select(x => new XElement("details", new object[] {
new XElement("interval", (string)x.Element("interval")),
new XElement("amount", (string)x.Element("amount"))
})).ToList();
template.Element("interval").Remove();
template.Element("amount").Remove();
template.Add(details);
newData.Add(template);
}
arrayOfData.ReplaceAll(newData);
}
}
}

How to extract data from SOAP response in C#

I have following SOAP response. Using my code I could only extract one element.
and then it throws null reference exception error.
How do I extract Item->key and Item->value in to my dictionary in the function in C#?
Following is a part of the function which i use to extract data from.
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP- ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:Magento" xmlns:ns2="http://xml.apache.org/xml-soap" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:callResponse>
<callReturn SOAP-ENC:arrayType="ns2:Map[2]" xsi:type="SOAP-ENC:Array">
<item xsi:type="ns2:Map">
<item>
<key xsi:type="xsd:string">state</key>
<value xsi:type="xsd:string">processing</value>
</item>
<item>
<key xsi:type="xsd:string">status</key>
<value xsi:type="xsd:string">processing</value>
</item>
<item>
<key xsi:type="xsd:string">protect_code</key>
<value xsi:type="xsd:string">ba8dd7</value>
</item>
<item>
<key xsi:type="xsd:string">shipping_firstname</key>
<value xsi:type="xsd:string">Roshan</value>
</item>
<item>
<key xsi:type="xsd:string">billing_name</key>
<value xsi:type="xsd:string">Roshan India</value>
</item>
<item>
<key xsi:type="xsd:string">shipping_name</key>
<value xsi:type="xsd:string">Roshan India</value>
</item>
<item>
<key xsi:type="xsd:string">order_id</key>
<value xsi:type="xsd:string">2</value>
</item>
</item>
</callReturn>
</ns1:callResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The codes,
try
{
XmlDocument xdoc = new XmlDocument();//xml doc used for xml parsing
xdoc.LoadXml(content); // --------> THIS IS WHERE I PASS SOAP RESPONSE
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
XmlNodeList xNodelst = xdoc.DocumentElement.SelectNodes("//item");
int nodes = xNodelst.Count;
dynamic item;
Dictionary<string, string> items = new Dictionary<string, string>();
foreach (XmlNode xn in xNodelst)
{
XmlNode itemnode = xn["item"];
if (itemnode != null) {
string key = itemnode["key"].InnerText;
string value = itemnode["value"].InnerText;
items.Add(key, value);
}
}
var ss = items;
return "";
}
catch (Exception e) {
return e.Message;
}
The xml has two level of the tag item. So you have to make sure you treat each level of the item tag separately. I used xml linq to get data and put results into a dictionary.
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 root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
XElement firstItem = doc.Descendants(ns + "item").FirstOrDefault();
Dictionary<string, string> dictItems = firstItem.Descendants(ns + "item")
.GroupBy(x => (string)x.Element("key"), y => (string)y.Element("value"))
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
}
}
}
I finally managed to make this work. I added all the namespaces in namespace manager variable. And used xPath to navigate through the XML as below,
XmlNodeList xNodelst = xdoc.DocumentElement.SelectNodes("//item[#xsi:type]",nsmgr);
This helped me to resolve my problem. I'm posting this here in case if anyone having similar issue.
Cheers!
string soapString = #"<soapenv:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:urn=""urn:Magento""><soapenv:Header/><soapenv:Body><urn:call soapenv:encodingStyle=""http://schemas.xmlsoap.org/soap/encoding/""><sessionId xsi:type=""xsd:string"">"+ssid +#"</sessionId><resourcePath xsi:type=""xsd:string"">sales_order.list</resourcePath><args xsi:type=""xsd:anyType""></args></urn:call></soapenv:Body></soapenv:Envelope>";
HttpResponseMessage response = await PostXmlRequest("http://localhost/M1/api.php", soapString);
string content = await response.Content.ReadAsStringAsync();
XmlDocument xdoc = new XmlDocument();//xml doc used for xml parsing
xdoc.LoadXml(content);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("ns1", "urn:Magento");
nsmgr.AddNamespace("ns2", "http://xml.apache.org/xml-soap");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/");
XmlNodeList xNodelst = xdoc.DocumentElement.SelectNodes("//item[#xsi:type]",nsmgr);
int nodes = xNodelst.Count;
Dictionary<int, IDictionary> items = new Dictionary<int, IDictionary>();
int n = 0;
foreach (XmlNode xn in xNodelst)
{
XmlNode itemnode = xn;
Dictionary<string, string> itemData = new Dictionary<string, string>();
foreach (XmlNode xn1 in itemnode)
{
string key = xn1["key"].InnerText;
string value = xn1["value"].InnerText;
itemData.Add(key, value);
}
items.Add(n, itemData);
n++;
}
return items;

C# XML Document Error (2,2) deserialize xml and storing to array

Aim:
- Deserialize data from an xml document and storing it as an array.
- Avoiding manually assigning the data to different strings.
- The xml document will be manually generated
public void DeserializeObject(string filename)
{
try
{
XmlSerializer deserializer = new XmlSerializer(typeof(string[]));
FileStream fs = new FileStream(filename, FileMode.Open);
string[] XmlData = (string[])deserializer.Deserialize(fs);
foreach (string p in XmlData)
{
Console.WriteLine(p);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The XML document is as follows
<?xml version="1.0" encoding="utf-8"?>
<Mapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Products>
<Product>
<software>Seiko</software>
</Product>
<Product>
<hardware>Martina</hardware>
</Product>
</Products>
</Mapping>
Thank you, found this solution
<?xml version="1.0" encoding="utf-8" ?>
<Locations>
<Location Name="Location1" IP="127.0.0.1"></Location>
<Location Name="Location2" IP="127.0.0.1"></Location>
<Location Name="Location3" IP="127.0.0.1"></Location>
<Location Name="Location4" IP="127.0.0.1"></Location>
<Location Name="Location5" IP="127.0.0.1"></Location>
</Locations>
using System.Xml.Linq;
class Program
{
static void Main(string[] args)
{
string[] strarr = GetStringArray("Locations.xml");
foreach (string str in strarr)
{
Console.WriteLine(str);
}
}
public static string[] GetStringArray(string url)
{
XDocument doc = XDocument.Load(url);
var locations = from l in doc.Descendants("Location")
select (string)l.Attribute("Name");
return locations.ToArray();
}
}
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication38
{
class Program
{
static void Main(string[] args)
{
string input =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<Mapping xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
"<Products>" +
"<Product>" +
"<software>Seiko</software>" +
"</Product>" +
"<Product>" +
"<hardware>Martina</hardware>" +
"</Product>" +
"</Products>" +
"</Mapping>";
XDocument doc = XDocument.Parse(input);
var results = doc.Descendants("Product").Select(x =>
x.Elements().Select(y => new { type = y.Name, value = (string)y }).ToList()
).SelectMany(z => z).ToList();
var groups = results.GroupBy(x => x.type).ToList();
}
}
}
You need to generate a class from your sample XML.
You can use the xsd.exe to generate a .xsd and from that create a .cs file.
The you need to add this type to your XmlSerializer
See this answer: Generate C# class from XML
XmlSerializer deserializer = new XmlSerializer(typeof(Mapping)); <- Created class type here.
If all you want to do is get the data form the XML-document as an array of strings, you can use XmlDocument to load in the data
XmlDocument doc = new XmlDocument();
doc.Load("file.xml");
Then you can find the nodes you need using an xPath expression:
XmlNodeList nodelist = doc.SelectNodes(...);

Categories