I'm actually playing around with the last.FM web serivce API which I call via REST. When I get the response I try to convert the result into a XDocument so I could use LINQ to work with it.
But when I pass the result string to the XDocumnet constructor an ArgumentException is thrown telling me that "Non white space characters cannot be added to content.". Unfortunately I'm very new to web services and XML programming so I don't really know how to interpret this exception.
I hope someone could give me a hint how to solve this problem.
It sounds to me as though you are holding the response in a string. If that is the case, you can try to use the Parse method on XDocument which is for parsing XML out of a string.
string myResult = "<?xml blahblahblah>";
XDocument doc = XDocument.Parse(myResult);
This may or may not solve your problem. Just a suggestion that is worth a try to see if you get a different result.
Here's a sample you can use to query the service:
class Program
{
static void Main(string[] args)
{
using (WebClient client = new WebClient())
using (Stream stream = client.OpenRead("http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=b25b959554ed76058ac220b7b2e0a026&artist=Cher&album=Believe"))
using (TextReader reader = new StreamReader(stream))
{
XDocument xdoc = XDocument.Load(reader);
var summaries = from element in xdoc.Descendants()
where element.Name == "summary"
select element;
foreach (var summary in summaries)
{
Console.WriteLine(summary.Value);
}
}
}
}
http://jamescrisp.org/2008/08/08/simple-rest-client/ has posted a little REST Client. Maybe a starting point for you.
Related
Can any one give me a proper explain why i am unable to get updated XML content from URL. I have a XML file which will frequently update. But in my application i am getting old data. Until i restart my application.
Here i am placing my code that i have tried
XmlDocument doc = new XmlDocument();;
string str;
using (var wc = new WebClient())
{
str = wc.DownloadString(location.AbsoluteUri);
}
doc.LoadXml(str);
And also tried with below code
WebRequest req = HttpWebRequest.Create("url");
using (Stream stream = req.GetResponse().GetResponseStream())
{
xmldoc.Load(stream);
}
I got to know that raw git hub take time to update in all servers so it is taking time to update. So you can use other web services to get result you want.
I have a very large xml-file (let's say it has about 300000 elements). In my part of the application I only have to know if the name of the root-element is ApplicationLog and if there is an attribute called LogId in the root-element.
To read the XML I use:
XDocument document;
using (StreamReader streamReader = new StreamReader(filePath, true))
{
document = XDocument.Load(streamReader);
}
and to get the information I need:
try
{
if (document.Root != null)
{
if (string.Equals(document.Root.Name.LocalName, "ApplicationLog", StringComparison.InvariantCultureIgnoreCase) &&
document.Root.HasAttributes && (from o in document.Root.Attributes() where string.Equals(o.Name.LocalName, "LogId", StringComparison.InvariantCultureIgnoreCase) select o).Any())
{
isRelevantFile = true;
}
}
}
catch (Exception e)
{
}
This just works fine.
The problem is that the XDocument.Load takes about 15 seconds to load a XML-File which is about 20MB.
I also tried it with the XmlDocument, but there I have the same problem.
My first idea for a solution was to read the file as text and parse the first lines for the searched element/attribute. But this seems to be not so professional to me.
Does anybody know a better way to achieve this?
Use the XmlReader API with
using (XmlReader xr = XmlReader.Create(filePath))
{
xr.MoveToContent();
if (xr.LocalName == "ApplicationLog" ...)
}
You can try the solution provided here or use/develop a SAX reader such as this one. You can find more information on SAX here.
I'm trying to call a method from a catch block but the xmlnode inside the method doesn't seem to work. I'm getting a null. If I call the same method from the try block it works.
var doc = new XmlDocument();
try
{
doc.Load(f.FullPath);
// do some work
}
catch (Exception e)
{
if (e is XMLException)
{
checkXML(ref doc);
}
public void checkXML(ref XmlDocument doc)
{
XmlNode xn = doc.SelectSingleNode("/BroadcastMonitor/Current");
xn["name1"].InnerText = SecurityElement.Escape(xn["name1"].InnerText);
xn["name2"].InnerText = SecurityElement.Escape(xn["name2"].InnerText); ;
}
Now when the catch block calls method 'checkXML', i get xn as null. But if I execute the same from the 'try' block just to check, 'xn' has a value. 'doc' too has a value regardless of when called try or from catch block.
Why is this happening? Please help me understand.
EDIT
<BroadcastMonitor>
<updated>2014-10-17T07:56:30</updated>
<Name>TESTING</Name>
<Current>
<artistName>اصاله& نصرى</artistName>
<albumName>شخصيه عنيده</albumName>
<CategoryName>ARABIC & SONGS</CategoryName>
</Current>
</BroadcastMonitor>
Thank you.
Your xml contains an & character which is not a 'valid' xml character and must be escaped.
<CategoryName>ARABIC & SONGS</CategoryName>
So it's causing your Load() method to throw the exception.
What you should do is escape all the invalid characters in your xml string before passing them on to an xml parser like so
yourXmlString = XmlConvert.EncodeName(yourXmlString);
You can then pass the yourXmlString on to the parser like so
var xDoc = XDocument.Parse(yourXmlString);
or if you don't want to or can't use the XDocument class you will need to make sure you save the xml encoded so that the Load() method of the XmlDocument class will be reading a file that is properly encoded.
Note that XmlDocument and XDocument classes are not the same thing and have some significant differences. Method Parse(), if I remember correctly, is one of the advantages that XDocument has over XmlDocument.
EDIT :
You can read the xml file into a string using the File class
var yourXmlString = File.ReadAllText(filePath);
XmlDocument is a reference type... no need to pass it with ref.
And my guess is that its failing to load in the first place so doc is really null
It looks like this document is missing its xml declaration tag.
try:
XmlDocument doc = new XmlDocument;
using(StreamReader reader = new StreamReader(f.FullPath))
{
doc.LoadXml(reader.ReadToEnd());
}
You can use System.IO.File.ReadAllText() to get all text from file into a string variable :
string invalidXml = System.IO.File.ReadAllText(f.FullPath);
For this particular XML, you can simply replace & with it's encoded version & to make a valid XML string :
string validXml = invalidXml.Replace("&", "&");
doc.LoadXml(validXml);
.....
Related question for reference : Reading XML with an "&" into C# XMLDocument Object
This would be my solution:
private static Regex InnerValues = new Regex(#"(?<=<(.*?>)).*?(?=</\1)",RegexOptions.Compiled);
private static XmlDocument LoadInvalidDocument(string path)
{
XmlDocument result = new XmlDocument();
string content = File.ReadAllText(path);
var matches = InnerValues.Matches(content);
foreach (Match match in matches)
{
content = content.Replace(match.Value, HttpUtility.HtmlEncode(match.Value));
}
result.LoadXml(content);
return result;
}
I have a piece of code which works well for normal files. But for really big files, it makes the server stop working.
Here it is:
XmlReader reader = null;
try
{
reader = XmlReader.Create(file_name + ".xml");
XDocument xml = XDocument.Load(reader);
XmlNamespaceManager namespaceManager = GetNamespaceManager(reader);
XElement root = xml.Root;
//XAttribute supplier = root.XPathSelectElement("//sh:Receive/sh:Id", namespaceManager).Attribute("Authority");
//string version = root.XPathSelectElement("//sh:DocumentId/sh:Version", namespaceManager).Value;
var nodes = root.XPathSelectElements("//eanucc:msg/eanucc:transact", namespaceManager);
return nodes;
}
catch
{ }
I think this is the part which causes the memory problem which happens on the server. How can I fix this?
It sounds like there's simply too much data to read in one go. You'll have to iterate over the elements one at a time, using XmlReader as a cursor, and converting one element to XElement at a time.
public static IEnumerable<XElement> ReadTransactions()
{
using (var reader = XmlReader.Create(file_name + ".xml"))
{
while (reader.ReadToFollowing("transact", eanuccNamespaceUri))
{
using (var subtree = reader.ReadSubtree())
{
yield return XElement.Load(subtree);
}
}
}
}
Note: this assumes there are never "transact" elements at any other level. If there are, you'll need to be more careful with your XmlReader than just calling ReadToFollowing. Also note that you'll need to find the actual namespace URI of the eanucc alias.
Don't forget that if you try to read all of this information in one go (e.g. by calling ToList()) then you'll still run out of memory. You need to stream the information. (It's not clear what you're trying to do with the elements, but you need to think about it carefully.)
Try putting the reader in a using(){} clause so it gets disposed of after use.
try
{
using(var reader = XmlReader.Create(file_name + ".xml"))
{
XDocument xml = XDocument.Load(reader);
XmlNamespaceManager namespaceManager = GetNamespaceManager(reader);
XElement root = xml.Root;
var nodes = root.XPathSelectElements("//eanucc:msg/eanucc:transact", namespaceManager);
return nodes;
}
}
catch
{ }
I'm trying to read a rss feed which uses the iso-8859-1 encoding.
I can get all elements fine, the problem is when I put it in a textblock it will not show all characters. I'm not sure what i'm doing wrong. i've tried a few solutions I found on google but this didn't work for me. I must be missing something.. It's also the first time I really work with anything other than utf-16. I never had to convert anything before.
The app works as follows I downloadstring async(WebClient). So when that is called I get a string containing the complete rss feed.
I have tried getting the bytes, then encoding.convert.. But I must be missing something.
Like this is a sample
WebClient RSS = new WebClient();
RSS.Encoding = Encoding.GetEncoding("ISO-8859-1");
RSS.DownloadStringCompleted += new DownloadStringCompletedEventHandler(RSS_DSC);
RSS.DownloadStringAsync(new Uri("some rss feed"));
public void RSS_DSC(object sender, DownloadStringCompletedEventArgs args)
{
_xml = XElement.Parse(args.Result);
foreach(XElement item in _xml.Elements("channel").Elements("item"))
{
feeditem.title = item.Element("title").Value;
// + all other items
}
}
I've tried this aswell
private void RSS_ORC(object sender, OpenReadCompletedEventArgs args)
{
Encoding e = Encoding.GetEncoding("ISO-8859-1");
Stream ez = args.Result;
StreamReader rdr = new StreamReader(ez, e);
XElement _xml = _xml = XElement.Parse(rdr.ReadToEnd());
feedlist = new List<Code.NewsItem>();
XNamespace dc = "http://purl.org/dc/elements/1.1/";
foreach (XElement item in _xml.Elements("channel").Elements("item"))
{
Code.NewsItem feeditem = new Code.NewsItem();
feeditem.title = item.Element("title").Value;
feeditem.description = item.Element("description").Value;
feeditem.pubdate = item.Element("pubDate").Value;
feeditem.author = item.Element(dc + "creator").Value;
feedlist.Add(feeditem);
}
listBox1.ItemsSource = feedlist;
}
Though titles contain characters that are not displayed well either. Like.. I can get the encoding to partially work. Instead of having these characters: the square with a question mark, a question mark or the singe square.
Don't get me wrong I'm a total beginner on this. But the solutions that has been posted on the web do not solve it for me.
Note that I removed the encoding part because it wasn't working :/
If someone would be able to help me that would be amazing.
You can specify an encoding by setting encoding before calling client.DownloadStringAsync:
webClient.Encoding = Encoding.GetEncoding("iso-8859-1")
In your code sample you do not create the XML doc anywhere. Are some code missing? You should initialize it with something like:
var xml = XDocument.Load((string)args.Result);
If it helps, you can use:
var myString = HttpUtility.HtmlDecode(feeditem.description);
This way every special character will be decode, you can then display myString correctly
Windows Phone 7 and Silverlight does not support other encodings such as ISO-8859-1, they only support ASCII and the Unicode encoders. For anything else you will need to use OpenReadAsync to get a stream of bytes then apply your own implementation of an encoding.
This blog might be helpful to you in creating one.
ISO-8859-1 most definitely is supported in WP7. It is the only one of the ISO-8859-* encodings that is. I use an XmlReader to deserialize RSS streams and UTF-* and ISO-8859-1 are the only encodings that are supported by that class (windows-* and ISO-8859-2 and above throw exceptions in the XmlReader c'tor).
Try using an XmlReader like this (without specifying the encoding):
using (XmlReader reader = XmlReader.Create(stream))
{
...
}
The XmlReader will get the encoding from the xml declaration in the stream.
You may still have problems displaying the upper half of the characters (above 0x80). I had this problem in feed me (my WP7 app) and used this little hack to fix things up:
public static string EncodeHtml(string text)
{
if (text == null) return string.Empty;
StringBuilder decodedText = new StringBuilder();
foreach (char value in text)
{
int i = (int)value;
if (i > 127)
{
decodedText.Append(string.Format("&#{0};", i));
}
else
{
decodedText.Append(value);
}
}
return decodedText.ToString();
}
It only works in a WebBrowser control of course, but that is the only place that I ever saw an incorrect display.
Hope this helps,
Calum
This worked for me when needing to decode the rss xml. It's generic enough so that it will support all encryption types supported by .NET
WebClient wcRSSFeeds = new WebClient();
String rssContent;
// Support for international chars
Encoding encoding = wcRSSFeeds.Encoding;
if (encoding != null)
{
encoding = Encoding.GetEncoding(encoding.BodyName);
}
else
{
encoding = Encoding.UTF8; // set to standard if none given
}
Stream stRSSFeeds = wcRSSFeeds.OpenRead(feedURL); // feedURL is a string eg, "http://blah.com"
using (StreamReader srRSSFeeds = new StreamReader(stRSSFeeds, encoding, false))
{
rssContent = srRSSFeeds.ReadToEnd();
}