I'm trying to load some xml into a XDocument. The XML data is provided by the city of Philadelphia, so that's not something I can change. I had a similar query before, which worked just fine. The xml response also seems to hold up in online XML validators, so how can I load it into my XDocument?
Here's the xml request
Here's my code, slightly simplified (first two lines taken and modified from another function).
string searchString = "http://services.phila.gov/PhillyApi/Data/v1.0/permits?$expand=locations&$filter=(issued_datetime%20gt%20Datetime%272012-12-01%27%20and%20issued_datetime%20le%20Datetime%272014-07-18%27)%20and%20(substringof(%27MAJOR%27,permit_type_code)%20or%20substringof(%27MINOR%27,permit_type_code)%20or%20substringof(%27PARIA%27,permit_type_code)%20or%20substringof(%27NEWCON%27,permit_type_code)%20or%20substringof(%27ENTIRE%27,permit_type_code))";
XDocument xResult = MakeRequest(searchString);
public static XDocument MakeRequest(string requestUrl)
{
HttpWebRequest request = WebRequest.Create(requestUrl) as HttpWebRequest;
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
// This line causes the error 'root element missing'
XDocument xDoc = XDocument.Load(response.GetResponseStream());
return (xDoc);
}
Related
I see several questions that are close to this but none exactly cover it:
How to apply an XSLT Stylesheet in C#
XSLT Transform of XML using Xml data from a web form
How to transform an xml structure generated from a request to a web services
I can cobble something together from these but I worry I am passing it through too many steps to be efficient.
What I currently have is this, to read XML from a HTTP web request:
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader streamReader = new StreamReader(stream);
string xml = streamReader.ReadToEnd();
This was before the need to apply an XLST transform was needed. Now I have a (possibly null) XslCompiledTransform object.
So I want to add a block like:
if(transform != null)
{
xml = transform.Transform(xml);
}
Clearly this isn't possible as written. I see StringReaders and XmlReaders can be created but is it inefficient to get my xml as a string and then push it back into another object? Can I use my stream or streamReader objects directly to support the same basic flow, but with optional transformation?
Personally I'd use the XmlDocument.Load() function to load the XML from the URL, without using WebRequest in this case.
You can pass the XmlDocument Straight to XSLCompiledTransform.Transform() then.
XmlDocument doc = new XmlDocument();
doc.Load(url);
if (transform != null)
{
XmlDocument tempDoc = new XmlDocument();
using (XmlWriter writer = tempDoc.CreateNavigator().AppendChild())
{
transform.Transform(doc, writer);
}
doc = tempDoc;
} //Use your XmlDocument for your transformed output
I'm getting geografic info from a webservice.
I'm trying to parse the return data for hours, but have been getting no where.
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string result = reader.ReadToEnd();
XDocument document = XDocument.Parse(result, LoadOptions.None);
i got this
document <html>
<body>
<state>Apure</state>
<municipality>RĂ“MULO GALLEGOS</municipality>
<parish>URBANA ELORZA</parish>
<street>La Trinidad De Arauca</street>
</body>
</html> System.Xml.Linq.XDocument
I try
document.Elements("state")
document.Descendants("body")
document.GetElementsByTagName("state");
But nothing.
I'm sure there is a simple way of do something so basic.
I'm seriously considering convert that to a string and do the parsing myself.
Aditional consideration:
The fields include it in the result is variable.
Because some info doesnt have all fields.
Ok, I make a change.
I read a XElement instead of a XDocument;
XElement sitemap = XElement.Parse(result, LoadOptions.None);
foreach (var bodyElement in sitemap.Elements("body"))
{
foreach (var fieldElement in bodyElement.Elements())
{
Console.WriteLine(fieldElement.Name);
Console.WriteLine(fieldElement.Value);
}
}
Probably there is a way to skip the first foreach, but still looking for it.
#Jonesy line works but that mean I have to know the fields names. This way i just create the info for the values I got.
I trying to convert JSON output into XML. Unfortunately I get this error:
JSON root object has multiple properties. The root object must have a single property in order to create a valid XML document. Consider specifing a DeserializeRootElementName.
This is what I up to now created.
string url = string.Format("https://graph.facebook.com/{0}?fields=posts.fields(message)&access_token={1}", user_name, access_token);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
jsonOutput = reader.ReadToEnd();
Console.WriteLine("THIS IS JSON OUTPUT: " + jsonOutput);
}
XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(jsonOutput);
Console.WriteLine(doc);
And this is my JSON output:
{"id":"108013515952807","posts":{"data":[{"id":"108013515952807_470186843068804","created_time":"2013-05-14T20:43:28+0000"},{"message":"TEKST","id":"108013515952807_470178529736302","created_time":"2013-05-14T20:22:07+0000"}
How can I solve this problem?
Despite the fact your JSON provided in the question is not complete, you have multiple properties at the top level as indicated by the exception. You have to define the root for it to get valid XML:
var doc = JsonConvert.DeserializeXmlNode(jsonOutput, "root");
EDIT: In order to print out your XML with indentation you can use XDocument class from System.Xml.Linq namespace: XDocument.Parse(doc.InnerXml).
I thought it's worth linking to the Documentation for turning xml to json and the other way around.
The guys are right..
// To convert an XML node contained in string xml into a JSON string
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
string jsonText = JsonConvert.SerializeXmlNode(doc);
// To convert JSON text contained in string json into an XML node
XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(json);
You can do JSON-to-XML also by using the .NET Framework (System.Runtime.Serialization.Json):
private static XDocument JsonToXml(string jsonString)
{
using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(jsonString)))
{
var quotas = new XmlDictionaryReaderQuotas();
return XDocument.Load(JsonReaderWriterFactory.CreateJsonReader(stream, quotas));
}
}
DeserializeXmlNode returns XDcument.
If needed XNode use FirstNode.
//string jsonOutput="{"id":"108013515952807","posts":{"data":[{"id":"108013515952807_470186843068804","created_time":"2013-05-14T20:43:28+0000"},{"message":"TEKST","id":"108013515952807_470178529736302","created_time":"2013-05-14T20:22:07+0000"}";
var myelement= JsonConvert.DeserializeXmlNode(jsonOutput, "myelement").FirstNode;
Your shared JSON is invalid please go through http://jsonformatter.curiousconcept.com/ and validate your JSON first.
Yourt JSON should look like:
{
"id":"108013515952807",
"posts":{
"data":[
{
"id":"108013515952807_470186843068804",
"created_time":"2013-05-14T20:43:28+0000"
},
{
"message":"TEKST",
"id":"108013515952807_470178529736302",
"created_time":"2013-05-14T20:22:07+0000"
}
]
}
}
Adding on #jwaliszko's answer, converting json to XDocument:
XDocument xml = JsonConvert.DeserializeXNode(json);
Lets say The following is my xml input that I receive from my webservice using this code:
string url = txtURL.Text;
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse rep = (HttpWebResponse)req.GetResponse();
XmlDocument doc = new XmlDocument();
doc.Load(rep.GetResponseStream());
rep.Close();
now I have the following xml document in the "doc"
<note>
<parent_element>
<child_element attribute_1="1">
<inner_element> first Text </inner_element>
</child_element>
<child_element attribute_1="2">
<inner_element> second Text </inner_element>
</child_element>
</parent_element>
</note>
Now I want to remove the first child element based on its attribute value. So if the attribute value of the child element is "1" then I want to delete "child_element" and all of its child elements. so my final result should look like this:
<note>
<parent_element>
<child_element attribute_1="2">
<inner_element> second Text </inner_element>
</child_element>
</parent_element>
</note>
Once I have removed the element, I would write it back to the webservice. I know i am asking for a lot, but havent been able to figure it out so far.
I would include my code, but since I am a newbie to xml manipulation, i think that will be of no use (sad face). Any help or direction will be appreciated.
Thank you guys.
First of all: doc.load(txtURL.Text) is enough to load the XML from a remote location.
You can delete a node like this:
XmlDocument doc = new XmlDocument();
doc.Load(filename);
//Select node that needs to be deleted
XmlNode node = doc.SelectSingleNode("/note/parent_element/child_element[#attribute_1 = '1']");
node.ParentNode.RemoveChild(node);
How you write all that back to your web application depends on what it is expecting. I will attach one example that POSTs a XML file against a RESTful web service
WebRequest req = WebRequest.Create(updateURL);
req.ContentType = "text/xml";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.Default.GetBytes(xmldoc);
req.ContentLength = bytes.Length;
Stream data = req.GetRequestStream();
data.Write(bytes, 0, bytes.Length);
data.Close();
I am doing task of loading the live xml file (from live url) to XmlDataDocument, but every time I am getting error:
The operation has timed out
The code is as follows, The url containing the xml feeds , I want to load it into xmlDoc.
XmlDataDocument xmlDoc = new XmlDataDocument();
xmlDoc.Load("http://www.globalgear.com.au/productfeed.xml");
Please suggest any solution.
Don't use the Load method of the XmlDataDocument class directly; you have little to no way of influencing the behaviour when it comes to long running HTTP requests.
Instead, use the HttpWebRequest and HttpWebResponse classes to do the work for you, and then load the subsequent response into your document.
For example:
HttpWebRequest rq = WebRequest.Create("http://www.globalgear.com.au/productfeed.xml") as HttpWebRequest;
//60 Second Timeout
rq.Timeout = 60000;
//Also note you can set the Proxy property here if required; sometimes it is, especially if you are behind a firewall - rq.Proxy = new WebProxy("proxy_address");
HttpWebResponse response = rq.GetResponse() as HttpWebResponse;
XmlTextReader reader = new XmlTextReader(response.GetResponseStream());
XmlDocument doc = new XmlDocument();
doc.Load(reader);
I've tested this code in a local app instance and the XmlDocument is populated with the data from your URL.
You can also substitute in XmlDataDocument for XmlDocument in the example above - I prefer to use XmlDocument as it's not (yet) marked as obsolete.
I've wrapped this in a function for you:
public XmlDocument GetDataFromUrl(string url)
{
XmlDocument urlData = new XmlDocument();
HttpWebRequest rq = (HttpWebRequest)WebRequest.Create(url);
rq.Timeout = 60000;
HttpWebResponse response = rq.GetResponse() as HttpWebResponse;
using (Stream responseStream = response.GetResponseStream())
{
XmlTextReader reader = new XmlTextReader(responseStream);
urlData.Load(reader);
}
return urlData;
}
Simply call using:
XmlDocument document = GetDataFromUrl("http://www.globalgear.com.au/productfeed.xml");
To my knowledge there is no easy way to adjust the timeout with the method you are using.
The easiest change would be to use the webclient class and set the timeout property. This is described here http://w3ka.blogspot.co.uk/2009/12/how-to-fix-webclient-timeout-issue.html. Then use downloadfile on the webclient. Then load the saved file in the XMLDocument.
Set a timeout for your web request:
using System;
using System.Net;
using System.Xml;
namespace Shelver
{
class Program
{
static void Main(string[] args)
{
WebRequest requ = WebRequest.Create("http://www.globalgear.com.au/productfeed.xml");
requ.Timeout = 10 * 60 * 1000; // 10 minutes timeout and not 100s as the default.
var resp = requ.GetResponse();
Console.WriteLine("Will download {0:N0}bytes", resp.ContentLength);
var stream = resp.GetResponseStream();
XmlDocument doc = new XmlDocument();
doc.Load(stream);
}
}
}
This example will set it to 10 minutes.
In addition to the previous answers, which should be the first step towards fixing this, I continued to get this exception despite having already loaded the response and closing the connections.
The solution for me: the Load() and LoadXml() methods would throw their own Timeout exception if the value provided wasn't actually XML. Checking to verify that the response content was XML worked in our case (this will require that the host you are getting your response from actually sets content types).
Building upon dash's answer:
public XmlDocument GetDataFromUrl(string url)
{
XmlDocument urlData = new XmlDocument();
HttpWebRequest rq = (HttpWebRequest)WebRequest.Create(url);
rq.Timeout = 60000;
HttpWebResponse response = rq.GetResponse() as HttpWebResponse;
// New check added to dash's answer.
if (response.ContentType.Contains("text/xml")
{
using (Stream responseStream = response.GetResponseStream())
{
XmlTextReader reader = new XmlTextReader(responseStream);
urlData.Load(reader);
}
}
return urlData;
}