I have a xml file which looks like below.
<sections>
<section>
<name>QLD Mosques</name>
<stations>
<station>
<id>101</id>
<pn>true</pn>
<name>Kuraby Mosque</name>
<url>http://sb2110.ultrastream.co.uk/kuraby</url>
<icon>...</icon>
</station>
<station>
<id>102</id>
<pn>true</pn>
<name>Gold Coast Mosque</name>
<url>http://sb2110.ultrastream.co.uk/goldcoast</url>
<icon>http://www.juju.net.au/mosquereceivers/images/icons/gc.jpg</icon>
</station>
<station>...</station>
</stations>
</section>
<section>
<name>NZ Mosques</name>
<stations>...</stations>
</section>
<section>
<name>Islamic Radio Stations</name>
<stations>...</stations>
</section>
</sections>
I want get show all the station name which has "section" named "QLD Mosques".
For example my result will be "Kuraby Mosque,Gold Coast Mosque,...".
How can i achieve the result??
N:B:
I can show the names under "section" tag(which gives the result QLD Mosques,NZ Mosques,Islamic Radio Stations) by using these code:
public static List<MyData> channel_main_list = new List<MyData>();
public MainChannelList()
{
InitializeComponent();
WebClient client = new WebClient();
client.OpenReadCompleted += client_OpenReadCompleted;
client.OpenReadAsync(new Uri("http://www.juju.net.au/mosquereceivers/Stations.xml",UriKind.Absolute));
}
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null)
return;
Stream str = e.Result;
string node = "section";
XDocument loadedData = XDocument.Load(str);
try
{
foreach (var item in loadedData.Descendants(node))
{
try
{
MyData m = new MyData();
m.channel_name = item.Element("name").Value;
channel_main_list.Add(m);
}
catch (Exception)
{
MessageBox.Show("Problem");
}
}
listBox.ItemsSource = channel_main_list;
}
catch (Exception)
{
MessageBox.Show("Connectivity Problem");
}
}
This is one possible way, assuming that the XML structure is consistent and name being searched is always found :
var result = loadedData.Descendants("section")
.Where(o => (string)o.Element("name") == "QLD Mosques")
.Elements("stations")
.Elements("station")
.Elements("name");
Dotnetfiddle Demo
Related
I need to process the data in an XML file similar to this:
<?xml version="1.0" encoding="utf-8"?>
<bpr:release xmlns:bpr="http://www.bp.co.uk/product/release">
<bpr:contents>
<process id="1" name="Process 1" xmlns="http://www.bp.co.uk/product/process">
<process name="Process 1"></process>
</process>
<process id="2" name="Process 2" xmlns="http://www.bp.co.uk/product/process">
<process name="Process 1"></process>
</process>
<object id="1" name="Object 1" xmlns="http://www.bp.co.uk/product/process">
<process name="Object 1" ></process>
</object>
<work-queue id="1" name="Queue1" xmlns="http://www.bp.co.uk/product/work-queue"/>
<process-group id="1" xmlns="http://www.bp.co.uk/product/process-group">
<members>
<process id="1"/>
<process id="2"/>
</members>
</process-group>
<object-group id="1" xmlns="http://www.bp.co.uk/product/object-group">
<members>
<object id="1"/>
<object id="2"/>
</members>
</object-group>
</bpr:contents>
</bpr:release>
For example, I need to extract the /bpr:release/bpr:contents/process/process nodes for analysis, but I get nulls or this error:
System.Xml.XPath.XPathException
HResult=0x80131943
Message=Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
Source=System.Xml
I see that the file has multiple anonymous namespaces, and there is the same namespace used twice. I've tried various combinations, for example:
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xmlPath);
var nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("bpr", "http://www.bp.co.uk/product/release");
nsmgr.AddNamespace("bpp", "http://www.bp.co.uk/product/process");
nsmgr.AddNamespace("bpo", "http://www.bp.co.uk/product/process");
nsmgr.AddNamespace("bpwq", "http://www.bp.co.uk/product/work-queue");
nsmgr.AddNamespace("bppg", "http://www.bp.co.uk/product/process-group");
nsmgr.AddNamespace("bpog", "http://www.bp.co.uk/product/object-group");
XmlNodeList p;
XmlNodeList r;
try { r = xmlDoc.SelectNodes("/bpr:release"); } catch { }
try { r = xmlDoc.SelectNodes("//bpr:release"); } catch { }
try { r = xmlDoc.SelectNodes("bpr:release"); } catch { }
try { r = xmlDoc.SelectNodes("/release"); } catch { }
try { r = xmlDoc.SelectNodes("//release"); } catch { }
try { r = xmlDoc.SelectNodes("release"); } catch { }
try { p = xmlDoc.SelectNodes("process"); } catch { }
try { p = xmlDoc.SelectNodes("bpp:process"); } catch { }
try { p = xmlDoc.SelectNodes("/process"); } catch { }
try { p = xmlDoc.SelectNodes("/bpp:process"); } catch { }
try { p = xmlDoc.SelectNodes("//process"); } catch { }
try { p = xmlDoc.SelectNodes("//bpp:process"); } catch { }
try { p = xmlDoc.SelectNodes("/bpr:release/bpr:contents/process/process"); } catch { }
What is the correct XPath to get each of the child nodes of bpr:release, bpr:contents, process/process, object/process, etc.? How to use the XMLNamespaceManager for this?
You're adding namespace prefix declarations to your XmlNamespaceManager, but you're not using nsmgr in your calls to SelectNodes().
try { r = xmlDoc.SelectNodes("/bpr:release", nsmgr); } catch { }
^^^^^^^
Fix up the other calls accordingly.
Note also that your first example XPath,
/bpr:release/bpr:contents/process/process
should be
/bpr:release/bpr:contents/bpp:process/bpp:process
given your declaration:
nsmgr.AddNamespace("bpp", "http://www.bp.co.uk/product/process");
Finally, you should remove duplicate prefix declarations (e.g. bpp/bpo) in some of the AddNamespace() calls.
See also
How does XPath deal with XML namespaces?
Difference between "//" and "/" in XPath?
I'm still learning in terms of C#
I'm currently working on a filter system and have an if statement list that prevents user to from performing any actions. Now is it that whenever the user submits an ID, my foreach is supposed to run through the list of already submitted ID's checking whether they exist already or not.
The bug is that when the user submits an already existing ID, it will not see the existing ID in the first run so it will create and fill in a node, but in the second run it does so it sends an error message & breaks the session.
My code:
private async void btnAddId_Click(object sender, RoutedEventArgs e)
{
XmlDocument Xdoc = new XmlDocument();
Xdoc.Load(xmldoc);
XmlNode NodeEl = Xdoc.SelectSingleNode("root/filter/filter_item");
XmlNode NodeList = Xdoc.SelectSingleNode("root/filter");
var root = XDocument.Load(xmldoc).Root;
var filter = root.Element("filter");
int parsedValue;
foreach (var f in filter.Descendants())
{
if (f.Value == tbAddId.Text)
{
MessageBox.Show("Value already exists in the orderlist!");
}
else if (!int.TryParse(tbAddId.Text, out parsedValue))
{
MessageBox.Show("Input isn't numeric!");
}
else if (tbAddId.Text == "")
{
MessageBox.Show("No value was given!");
}
else if (tbAddId.Text == "Add ID")
{
MessageBox.Show("No value was given!");
}
else if (NodeList.InnerText == "")
{
NodeEl.InnerText = tbAddId.Text;
tbAddId.Text = "Add ID";
tbAddId.Foreground = Brushes.Gray;
await api.config_Load();
await api.Page_Load();
}
else
{
XmlNode filterItem = Xdoc.CreateElement("filter_item");
NodeList.AppendChild(filterItem);
filterItem.InnerText = tbAddId.Text;
}
tbOrderDisplay.Text += f.Value + " ";
}
Xdoc.Save(xmldoc);
}
XML content
<?xml version="1.0"?>
<root>
<bol_client_id></bol_client_id>
<!--- this is the client id-->
<bol_client_secret></bol_client_secret>
<!-- this is the client secret -->
<customer_id></customer_id>
<company_phone></company_phone>
<auth_token_url></auth_token_url>
<bol_orders_url></bol_orders_url>
<debug_mode>true</debug_mode>
<filter>
<filter_item>1172828940</filter_item>
<filter_item>1173700637</filter_item>
</filter>
</root>
Check whether value exists before you try to insert it:
private async void btnAddId_Click(object sender, RoutedEventArgs e)
{
XmlDocument Xdoc = new XmlDocument();
Xdoc.Load(xmldoc);
XmlNode NodeEl = Xdoc.SelectSingleNode("root/filter/filter_item");
XmlNode NodeList = Xdoc.SelectSingleNode("root/filter");
var root = XDocument.Load(xmldoc).Root;
var filter = root.Element("filter");
int parsedValue;
//1. Check for duplicates
foreach (var f in filter.Descendants())
{
if (f.Value == tbAddId.Text)
{
MessageBox.Show("Value already exists in the orderlist!");
tbOrderDisplay.Text += f.Value + " ";
return;
}
}
//2. Validate and insert
if (!int.TryParse(tbAddId.Text, out parsedValue))
{
MessageBox.Show("Input isn't numeric!");
}
else if (tbAddId.Text == "")
{
MessageBox.Show("No value was given!");
}
else if (tbAddId.Text == "Add ID")
{
MessageBox.Show("No value was given!");
}
else if (NodeList.InnerText == "")
{
NodeEl.InnerText = tbAddId.Text;
tbAddId.Text = "Add ID";
tbAddId.Foreground = Brushes.Gray;
await api.config_Load();
await api.Page_Load();
}
else
{
XmlNode filterItem = Xdoc.CreateElement("filter_item");
NodeList.AppendChild(filterItem);
filterItem.InnerText = tbAddId.Text;
}
Xdoc.Save(xmldoc);
}
I'm using this code to save and restore the XML values but I'm in trouble . Rescue usually works the problem and when I try to load the XML . I get this exception that in the image.
line 105 : string text = el.Attribute("Text").Value;
void SaveData() {
XDocument xmlDocument = new XDocument(new XElement("Pages"));
List<XElement> xmlPages = new List<XElement>();
foreach(KeyValuePair<string, string> doc in documents)
xmlDocument.Root.Add(
new XElement("Page",
new XAttribute("nodeName", GetNodeName(doc.Key)),
new XAttribute("pageGuid", doc.Key),
new XAttribute("Rtf", doc.Value)));
xmlDocument.Root.Add(
new XElement("TextEdit",
new XAttribute("Text", textBox1.Text)));
xmlDocument.Save(GetPathToFile());
}
void LoadData() {
try {
XDocument xmlDocument = XDocument.Load(GetPathToFile());
rootNode.Nodes.Clear();
documents.Clear();
foreach(XElement el in xmlDocument.Root.Elements()) {
string nodeName = el.Attribute("nodeName").Value;
string pageGuid = el.Attribute("pageGuid").Value;
string rtf = el.Attribute("Rtf").Value;
string text = el.Attribute("Text").Value;
rootNode.Nodes.Add(new DataNode(nodeName, pageGuid));
documents.Add(pageGuid, rtf);
textBox1.Text = text;
}
} catch(Exception ex) {
MessageBox.Show("No data loaded. Check XML file" + ex.ToString());
}
treeList1.RefreshDataSource();
}
The exception is clear: There is not such attribute el.Attribute("Text"), so you can't try to get it's value. Check for attribute existence before getting it's value.
After research could solve the case.
Solution:
void LoadData() {
try {
XDocument xmlDocument = XDocument.Load(GetPathToFile());
rootNode.Nodes.Clear();
documents.Clear();
foreach(XElement el in xmlDocument.Root.Elements()) {
switch(el.Name.LocalName) {
case "Page":
string nodeName = el.Attribute("nodeName").Value;
string pageGuid = el.Attribute("pageGuid").Value;
string rtf = el.Attribute("Rtf").Value;
rootNode.Nodes.Add(new DataNode(nodeName, pageGuid));
documents.Add(pageGuid, rtf);
break;
case "Text":
textEdit1.Text = el.Attribute("text").Value;
break;
}
}
} catch(Exception ex) {
MessageBox.Show("No data loaded. Check XML file");
}
treeList1.RefreshDataSource();
}
my source like this in C#:
string xml = null;
WebRequest req = WebRequest.Create("https://www.freegeoip.net/xml");
req.Credentials = CredentialCache.DefaultCredentials;
WebResponse res = req.GetResponse();
Stream dataStream = res.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
xml = reader.ReadToEnd();
reader.Close();
res.Close();
am getting response like this :
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>
/// XMl Reponse END///////////////////////////////
I want pass parameters to Database like :
objLogDetails.IPAddress = ???? //Here i want to pass IP :162.158.50.10 from XMl string
HEre are two methods, one using xpath and the other using linq 2 xml:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
namespace stackexchange
{
class Program
{
private static string theXml = #"<?xml version='1.0' encoding='UTF-8'?>
<Response>
<IP>162.158.50.10</IP> //IP address
<CountryCode>IN</CountryCode> //Country Code
<CountryName>India</CountryName>//Country Name
<RegionCode>MH</RegionCode> //Region Code
<RegionName>Maharashtra</RegionName>
<City>Mumbai</City>
<ZipCode></ZipCode>
<TimeZone>Asia/Kolkata</TimeZone>
<Latitude>18.975</Latitude>
<Longitude>72.8258</Longitude>
<MetroCode>0</MetroCode>
</Response>";
static void Main(string[] args)
{
XmlDocument xml = new XmlDocument();
xml.LoadXml(theXml);
XmlNode ip = xml.SelectSingleNode("/Response/IP");
Console.Out.WriteLine($"Ip Address: {ip.InnerText}");
XElement root = XElement.Parse(theXml);
XElement address = (from a in root.Descendants() where a.Name == "IP" select a).Single();
Console.Out.WriteLine($"Ip Address: {address.Value}");
}
}
}
What you can do here, is use an XElement to get items from the response and insert into your request.
You can do so like this:
//sets the node or remove
public static void SetOrRemoveNodeValue(XElement root, string xPath, string attributeName, string value)
{
XElement currentNode = root.XPathSelectElement(xPath);
if (currentNode != null)
{
if (currentNode.Attributes().FirstOrDefault(att => att.Name.LocalName.Equals(attributeName)) != null)
{
if (value == string.Empty)
{
currentNode.Attribute(attributeName).Remove();
}
else
{
currentNode.Attribute(attributeName).Value = value;
}
}
then use it like this:
Formatter.SetOrRemoveNodeValue("node", "your value type", "your value");
To extract value from the response, simply use:
currentNode.XPathSelectElement("//Response").Element("Ip").value;
Or simply
currentNode.XPathSelectElement("//Ip").value;
Trying This Code ..
private string mStrXMLStk = Application.StartupPath + "\\Path.xml";
private System.Xml.XmlDocument mXDoc = new XmlDocument();
mXDoc.Load(mStrXMLStk);
XmlNode XNode = mXDoc.SelectSingleNode("/Response");
if (XNode != null)
{
if (XNode != null)
{
int IntChildCount = XNode.ChildNodes.Count;
for (int IntI = 1; IntI <= 1; IntI++)
{
string LocalName = XNode.ChildNodes[IntI].LocalName;
XmlNode Node = mXDoc.SelectSingleNode("/Response/" + LocalName);
string _ip = Node.InnerText;
MessageBox.Show("IP" + _ip);
}
}
}
Completely worked
I am trying to parse some XML, however, I get the error above this sentence.
Here is my code:
class Program
{
static void Main(string[] args)
{
string xml = #"<?xml version=""1.0"" encoding=""UTF-8""?><rss version=""2.0"" xmlns:georss=""http://www.georss.org/georss"">
<channel>
<title>asp.net Jobs in Boston, MA | Indeed.com</title>
<link>http://www.indeed.com/q-asp.net-l-boston,-jobs.html</link>
<description>Indeed.com - one search. all jobs. Search thousands of sites for asp.net Jobs in Boston, MA</description>
<language>en</language>
<copyright>Copyright (c) 2012 Indeed, Inc All rights reserved.</copyright>
<lastBuildDate>Sun, 25 Mar 2012 19:43:15 GMT</lastBuildDate>
<image>
<url>http://www.indeed.com/images/indeed_rss.png</url>
<title>Indeed.com - one search. all jobs.</title>
<link>http://www.indeed.com/</link>
</image>
<item>
<title>Software Engineer with ASP.Net applications experience - The Integrity Group - Andover, MA</title>
<link>http://www.indeed.com/job/Software-Engineer-With-ASP-Net-Application-Experience-at-The-Integrity-Group-in-Andover,-MA-6ab16ba39cc13536</link>
<source>JobHost</source>
<guid isPermaLink=""false"">d61c3504e9df0fc13be4abb4be209c38</guid>
<pubDate>Wed, 21 Mar 2012 05:04:47 GMT</pubDate>
<description>layers and preferably service based architecture. ASP.Net web applications with server-side controls and... Solid experience in ASP.Net, SQL Server, C#, XML, XML... <br/>
From JobHost - 21 Mar 2012 05:04:47 GMT
- View all <a href="http://www.indeed.com/l-Andover,-MA-jobs.html">Andover jobs</a>
</description>
<georss:point>42.64835 -71.15934</georss:point>
</item>
</channel></rss>";
foreach (SavedJob sj in GetJobs(xml))
{
Console.WriteLine(sj.title);
}
}
public static List<SavedJob> GetJobs(string xml)
{
//http://forum.unity3d.com/threads/31314-Include-Files-in-build
XmlDocument xmlDoc = new XmlDocument();
System.IO.StringReader stringReader = new System.IO.StringReader(xml);
stringReader.Read();
//http://unity3d.qatohost.com/questions/161528/loading-a-large-xml-file-200-multi-level-nodes-int.html
// skip BOM
xmlDoc.LoadXml(stringReader.ReadToEnd());
List<SavedJob> SavedJobs = new List<SavedJob>();
try
{
foreach (XmlElement found in xmlDoc.GetElementsByTagName("item"))
{
SavedJob sj = new SavedJob();
sj.title = found.GetElementsByTagName("title")[0].InnerText;
sj.link = found.GetElementsByTagName("link")[0].InnerText;
sj.description = found.GetElementsByTagName("description")[0].InnerText;
DateTime dt = new DateTime();
DateTime.TryParse(found.GetElementsByTagName("pubDate")[0].InnerText, out dt);
sj.date = dt;
SavedJobs.Add(sj);
}
}
//data source is null
catch (Exception)
{
}
return SavedJobs;
}
}
public class SavedJob
{
public string title { get; set; }
public string link { get; set; }
public string description { get; set; }
public DateTime date { get; set; }
}
My goal is to create a loading panel in MonoTouch, however, I can't seem to download the string because the XML is bad. Is there a way around this?
LoadingView lv = new LoadingView ();
WebClient wc = new WebClient ();
wc.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e) {
// We got the async result now display data
InvokeOnMainThread (delegate {
if (e.Result != null) {
SavedJobs = basicOperations.GetJobs (e.Result);
TableView.Source = new DataSource (this);
TableView.ReloadData();
lv.Hide ();
}
});
};
lv.Show ("Loading");
wc.DownloadStringAsync (new Uri (uString));
Your code shows:
System.IO.StringReader stringReader = new System.IO.StringReader(xml);
stringReader.Read();
xmlDoc.LoadXml(stringReader.ReadToEnd());
What this does is:
create a string reader on ""
then read the first character - "<"
then try to load the remaining characters as xml - i.e. "xml ...>"
So you need to avoid the initial stringReader.Read(); call which is stripping the first opening angle bracket from the xml - making it invalid at 1,1
An even better way of doing this is creating a file from DownloadFileAsync:
WebClient wc = new WebClient();
string fPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "/myfile.xml";
wc.DownloadFileCompleted += delegate(object sender, AsyncCompletedEventArgs e) {
BasicOperations bas = new BasicOperations();
//save results as file
SavedJobs = bas.GetJobs(fPath);
TableView.Source = new DataSource (this);
TableView.ReloadData();
};
wc.DownloadFileAsync(new Uri(uString), fPath);