c# parse soap response when namespace prefix and xmlns prefix not equal - c#

Hello I'm completely stuck, I could manage somehow get response from remote service.svc wsdl. Sorry for poor English.
there is my working sample, thanks to stackoverflow:
using System;
using System.Xml;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string responseXml =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<Envelope" +
" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
"<soap:Body>" +
"<Company xmlns:b=\"http://www.someurl.com/Report/Company\">" +
"<b:LoginResult>" +
"<b:CookieName>FedAuth</b:CookieName>" +
"<b:ErrorCode>NoError</b:ErrorCode>" +
"<b:TimeoutSeconds>1800</b:TimeoutSeconds>" +
"<b:Parametrs>Zoroo 100</b:Parametrs>" +
"</b:LoginResult>" +
"</Company>" +
"</soap:Body>" +
"</Envelope>";
XmlDocument document = new XmlDocument();
document.LoadXml(responseXml); //loading soap message as string
XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
manager.AddNamespace("b", "http://www.someurl.com/Report/Company");
XmlNodeList xnList = document.SelectNodes("//b:LoginResult", manager);
int nodes = xnList.Count;
foreach (XmlNode xn in xnList)
{
string CookieName = xn["b:CookieName"].InnerText;
string ErrorCode = xn["b:ErrorCode"].InnerText;
string TimeoutSeconds = xn["b:TimeoutSeconds"].InnerText;
string Parametrs = xn["b:Parametrs"].InnerText;
Console.WriteLine();
Console.WriteLine(CookieName + ErrorCode + TimeoutSeconds + Parametrs);
Console.WriteLine();
}
}
}
}
My problem is that I cannot understand soap response message when I receive it like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<GCRResponse xmlns="http://www.someurl.com/Report">
<GCRResult xmlns:a="http://www.someurl.com/CReport" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Company xmlns:b="http://www.someurl.com/Company">
<b:General>
<b:SomeInfo xmlns:c="http://www.someurl.com/Report/Common">
<c:Curr>BUM</c:Curr>
<c:LocalValue>1.00</c:LocalValue>
<c:Value>1.00</c:Value>
</b:SomeInfo>
<b:BS>Active</b:BS>
<b:CName>Zabis</b:CName>
<b:ES>NotSpecified</b:ES>
<b:NACELookup>
<a:NACE>NotSpecified</a:NACE>
</b:NACELookup>
<b:PC xmlns:c="http://www.someurl.com/Report/Common">
<c:Curr>BUM</c:Curr>
<c:LocalValue>1.00</c:LocalValue>
<c:Value>1.00</c:Value>
</b:PC>
</b:General>
</a:Company>
<a:CompanyRep i:nil="true" xmlns:b="http://www.someurl.com/Report/SomeReport"/>
<a:Parameters>
<a:Consent>true</a:Consent>
<a:IDNumber>30103331133</a:IDNumber>
<a:IDNumberType>RNumber</a:IDNumberType>
<a:InquiryReason>Application</a:InquiryReason>
<a:ReportDate>2017-09-26T08:57:26.6885118+03:00</a:ReportDate>
<a:Sections xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:string>SubjectInfo</b:string>
</a:Sections>
<a:SubjectType>Company</a:SubjectType>
</a:Parameters>
<a:ReportInfo xmlns:b="http://www.someurl.com/Report/ReportInfo">
<b:Created>2017-09-26T08:57:26.7197686+03:00</b:Created>
<b:ReferenceNumber>333368-9543457</b:ReferenceNumber>
<b:ReportStatus>ReportGenerated</b:ReportStatus>
<b:RequestedBy i:nil="true"/>
<b:Subscriber i:nil="true"/>
<b:Version>325</b:Version>
</a:ReportInfo>
</GCRResult>
</GCRResponse>
</s:Body>
</s:Envelope>
how to access to values if I have namespace with different prefix (a,b) than xmlns prefix for example here
<a:Company xmlns:b="http://www.someurl.com/Company">
and I cannot figure out how to work with manager.AddNamespace in this case when a:Company and is xmlns:b
How to access all values a,b,c?

Related

How to extract elements from string as xml and return part of the element's value

I am planning on extracting the id based on the message, the id holds, in a log file. For eg: if the message is "Application started", i should associate the id for the message and return in an inenumerable list.
Here is my xml string:
String xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<log>\n" +
" <entry id=\"1\">\n" +
" <message>Application started</message>\n" +
" </entry>\n" +
" <entry id=\"2\">\n" +
" <message>Application ended</message>\n" +
" </entry>\n" +
"</log>";
And in my main method, I am calling the GetIDsByMessage to read through the string :
foreach (int id in LogParser.GetIdsByMessage(xml, "Application ended"))
Console.WriteLine(id);
And i am defining my GetIdsByMessage as :
public static IEnumerable<int> GetIdsByMessage(string xml, string message)
{
// write to return id {2} for message="Application ended"
}
I tried parsing the string as xml like this:
XmlDocument xmltest = new XmlDocument();
xmltest.LoadXml(xml);
XmlNodeList elemlist = xmltest.GetElementsByTagName("message");
But I am not sure how to collect all the ids and return it back to the caller. Any pointers ?
Here's my full code:
public class LogParser
{
public static IEnumerable<int> GetIdsByMessage(string xml, string message)
{
// write to return id {2} for message="Application ended"
XmlDocument xmltest = new XmlDocument();
xmltest.LoadXml(xml);
XmlNodeList elemlist = xmltest.GetElementsByTagName("message");
}
public static void Main(string[] args)
{
String xml =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<log>\n" +
" <entry id=\"1\">\n" +
" <message>Application started</message>\n" +
" </entry>\n" +
" <entry id=\"2\">\n" +
" <message>Application ended</message>\n" +
" </entry>\n" +
"</log>";
foreach (int id in LogParser.GetIdsByMessage(xml, "Application ended"))
Console.WriteLine(id);
}
}
Thanks
You could easily use Linq-to-XML:
public static IEnumerable<int> GetIdsByMessage(string xml, string message) =>
XDocument
.Parse(xml)
.Root
.Descendants("message")
.Where(x => x.Value == message)
.Select(x => (int)x.Parent.Attribute("id"));

Repeated writing in different XMLfiles

I need to write GPS-Data in different XMLfiles. The files need to have the following format:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<gpx>
<metadata>
<time>YYYY-MM-DDTHH:MM:SSZ</time>
</metadata>
<trk>
<name>YYYY-MM-DDTHH:MM:SSZ</name>
<trkseg>
<trkpt lat="12.1795" lon="12.3456">
<ele>-46.97</ele>
<time>YYYY-MM-DDTHH:MM:SSZ</time>
</trkpt>
// more trkpt
</trkseg>
</trk>
</gpx>
I tried to do it with an XMLwriter. At first it constructs the part till trkpt.That works. The XmlWriterSettings were included because the Error told me to use ConformanceLevel "Auto" or "fregmented" ,but that didn't solve my issue.
XmlWriterSettings setting = new XmlWriterSettings();
setting.ConformanceLevel = ConformanceLevel.Auto;
setting.Indent = true;
DateTime localDate = DateTime.Now;
xmlWriter[0] = XmlWriter.Create("testbase.xml", setting);
for (int i = 1; i < (numOfXMLWriter); i++)
{
xmlWriter[i] = XmlWriter.Create(test[i].Text, setting);
}
int tmp = 0;
foreach (XmlWriter writer in xmlWriter)
{
writer.WriteStartDocument(true);
writer.WriteStartElement("gpx");
writer.WriteStartElement("metadata");
writer.WriteStartElement("time");
writer.WriteString(localDate.Year + "-" + localDate.Month + "-" + localDate.Day + "T" + localDate.Hour + ":" + localDate.Minute + ":" + localDate.Second);
writer.WriteEndElement(); //time
writer.WriteEndElement(); //metadata
//trk + name
writer.WriteStartElement("trkseg");
}
Later the received GPS-Data is written as individual trkpt.
xmlWriter[id].WriteStartElement("trkpt");
xmlWriter[id].WriteAttributeString("lat", splitData[4]);
xmlWriter[id].WriteAttributeString("lon", splitData[6]);
xmlWriter[id].WriteStartAttribute("ele");
xmlWriter[id].WriteString("0");
xmlWriter[id].WriteEndElement(); //</ele>
xmlWriter[id].WriteStartElement("time");
xmlWriter[id].WriteString(splitData[10][4] + splitData[10][5] + "-" + splitData[10][2] + splitData[10][3] + "-" + splitData[10][0] + splitData[10][1] + "T" + splitData[2][0] + splitData[2][1] + ":" + splitData[2][2] + splitData[2][3] + ":" + splitData[2][4] + splitData[2][5] + "Z");
xmlWriter[id].WriteEndElement(); //</time>
xmlWriter[id].WriteEndElement(); //</trkpt>
The Error says:
InvalidOperationException: "Token StartElement in state EndRootElement would result in an invalid XML document”
I think this is because the XMLwriter Closes all the nodes atomatically and later i try to add another Node on root Level. Is there a possibility to stap the writer from ending the document on it's own?
Thanks for your help!
Jonas
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
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
string header = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?><gpx></gpx>";
XDocument doc = XDocument.Parse(header);
XElement gpx = doc.Root;
gpx.Add(new object[] {
new XElement("metadata"), new XElement("time", DateTime.Now.ToString("yyyy-MM-ddthh:mm:ssz")),
new XElement("trk", new object[] {
new XElement("name", DateTime.Now.ToString("yyyy-MM-ddthh:mm:ssz")),
new XElement("trksseg", new object[] {
new XElement("trkpt", new object[] {
new XAttribute("lat", 12.1795),
new XAttribute("lon", 12.3456),
new XElement("ele", -46.97),
new XElement("time",DateTime.Now.ToString("yyyy-MM-ddthh:mm:ssz")),
})
})
})
});
}
}
}

Extract Xdocument soap response body into new Xdocument

I have XML which is parsed into an XDocument:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<MyResponse xmlns="https://www.domain.net/">
<Node1>0</Node1>
</MyResponse>
</soap:Body>
</soap:Envelope>
Basically I am trying to create a new XDocument which has its root as
<MyResponse xmlns="https://www.domain.net/">
<Node1>0</Node1>
</MyResponse>
So in essence I am trying to extract this from the soap body. I have tried parsing this using Linq but cannot seem to return a new XDocument with this new root. Any ideas?
Thanks in advance
I think this will do the trick:
using System;
using System.Xml.Linq;
namespace SO39545160
{
class Program
{
static string xmlSource = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
"<soap:Body>" +
"<MyResponse xmlns = \"https://www.domain.net/\" >" +
"<Node1 > 0 </Node1 >" +
"</MyResponse>" +
"</soap:Body>" +
"</soap:Envelope>";
static void Main(string[] args)
{
XDocument xdoc = XDocument.Parse(xmlSource);
var subXml = xdoc.Document.Elements(XName.Get(#"{http://schemas.xmlsoap.org/soap/envelope/}Envelope")).Elements(XName.Get(#"{http://schemas.xmlsoap.org/soap/envelope/}Body")).Elements(XName.Get(#"{https://www.domain.net/}MyResponse"));
foreach (var node in subXml)
{
XDocument myRespDoc = new XDocument(node);
Console.WriteLine(myRespDoc);
}
Console.WriteLine();
Console.WriteLine("END");
Console.ReadLine();
}
}
}

Get Innertext from an XML string which has only one node without looping

I have an XML string which looks like below
<?xml version="1.0" encoding="Windows-1252"?><Product><ID>0701161476416</ID><UNIQUE_ID>test26051602</UNIQUE_ID><STATUS>DONE</STATUS></Product>
It is know that my XML string will always has a single node ans so I do not want to look, instead I would like to get Unique_ID and Status inner values without looping.
May I know a better way to do it and I do have the below code which actually loops through each node
XmlDocument xm = new XmlDocument();
xm.LoadXml(XML_STRING);
XmlNodeList xnList = xm.SelectNodes("/Product/Product");
foreach (XmlNode xn in xnList)
{
string uniqueID = xn["UNIQUE_ID"].InnerText;
string status = xn["STATUS"].InnerText;
}
There is SelectSingleNode() which you can use for this purpose :
XmlNode product = xm.SelectSingleNode("/Product/Product");
string uniqueID = product["UNIQUE_ID"].InnerText;
string status = product["STATUS"].InnerText;
Or, if Product is the root element, then you can access it from DocumentElement property of the XmlDocument :
XmlNode product = xm.DocumentElement;
string uniqueID = product["UNIQUE_ID"].InnerText;
string status = product["STATUS"].InnerText;
If you have more than one product try 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 =
"<?xml version=\"1.0\" encoding=\"Windows-1252\"?>" +
"<Products>" +
"<Product>" +
"<ID>0701161476416</ID>" +
"<UNIQUE_ID>test26051603</UNIQUE_ID>" +
"<STATUS>DONE</STATUS>" +
"</Product>" +
"<Product>" +
"<ID>0701161476417</ID>" +
"<UNIQUE_ID>test26051604</UNIQUE_ID>" +
"<STATUS>DONE</STATUS>" +
"</Product>" +
"<Product>" +
"<ID>0701161476418</ID>" +
"<UNIQUE_ID>test26051605</UNIQUE_ID>" +
"<STATUS>DONE</STATUS>" +
"</Product>" +
"</Products>";
XDocument doc = XDocument.Parse(xml);
var results = doc.Descendants("Product").Select(x => new
{
id = (long)x.Element("ID"),
uniqueID = (string)x.Element("UNIQUE_ID"),
status = (string)x.Element("STATUS")
}).ToList();
}
}
}
This could work, but I guess there is a better solution:
XDocument xm = XDocument.Parse(XML_STRING);
var product = xm.Element("Product").Element("Product");
string uniqueID = product.Element("UNIQUE_ID").Value;
string status = product.Element("STATUS").Value;
Your SelectNodes line seemed wrong for the sample Xml.
XmlNodeList xnList = xm.SelectNodes("/Product");
if (xnList.Count > 0)
{
string uniqueID = xnList[0]["UNIQUE_ID"].InnerText;
string status = xnList[0]["STATUS"].InnerText;
}

How to get an XML value out of another XML value at C#

I need to get a value out of an XML file...
I have this XML file for example:
<?xml version="1.0"?>
<hwids>
<user>
<userName>Ivar</userName>
<hwid>BFEB-FBFF-0000-06FD-C87C-FA30</hwid>
</user>
<user>
<userName>Jerremy</userName>
<hwid>BFE9-FBFF-0000-06E8-E41E-5034</hwid>
</user>
</hwids>
Now, if I have the value BFEB-FBFF-0000-06FD-C87C-FA30, how do I get the name Ivar, out of the xml file trough C#?
I used in my application something like this:
using System.Data;
DataSet dataSet = new DataSet();
dataSet.ReadXml(xmlFullPath, XmlReadMode.Auto);
DataRow[] dataRows = dataSet.Tables["user"].Select("hwid like 'BFEB-FBFF-0000-06FD-C87C-FA30'");
if (dataRows.Length == 0)
return;
string sUser = dataRows[0]["userName"].ToString();
you can accomplish this also with XmlDocument of the System.Xml namespace, which is supported in .NET 3.0
var xml = "<?xml version=\"1.0\"?>" +
"<hwids> " + "<user>" +
"<userName>Ivar</userName>" +
"<hwid>BFEB-FBFF-0000-06FD-C87C-FA30</hwid>"+
"</user> " +
"<user>" +
"<userName>Jerremy</userName>" +
"<hwid>BFE9-FBFF-0000-06E8-E41E-5034</hwid>" +
"</user>" +
"</hwids>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var ret = doc.GetElementsByTagName("userName");
for (int i = 0; i < ret.Count; i++)
{
Debug.WriteLine(ret.Item(i).InnerText);
}
I think this should work:
XElement root = XElement.Load("file.xml");
IEnumerable<XElement> hws =
from el in root.Elements("user")
where (string)el.Element("userName") == "Ivar"
select el.Descendant("hwid);
Haven't tested it out.

Categories

Resources