Reading Identical elements using XPathNavigator
-
Tuesday, April 17, 2012 11:09 AM
I am using XPathDocument to read xml. XML Document format is given below. You can see that there are two similar elements with name of <g:image_link> ...how can i read identical elements?my current code only gets first image_link not second one. snippet of my program along with xml is given below
/////////////////////Main code/////////////////////////////
static private XPathDocument _doc;
static private XPathNavigator _nav;
static private XPathNavigator nav2;
static private XPathNodeIterator iterator;
static private RssXmlReader rssXmlReader;
_doc = new XPathDocument(_rssReaderUri);
_nav = _doc.CreateNavigator();
XPathExpression expr;
expr = _nav.Compile("/rss/channel/item");
iterator = _nav.Select(expr);
try
{
while (iterator.MoveNext())
{
nav2 = iterator.Current.Clone();
string gns = nav2.LookupNamespace("g");
string cns = nav2.LookupNamespace("c");
RssItemData temp = new RssItemData();temp.Image_Link = "image_link@" + gns;
}
////////// RssItemData class snippet.//////////////////
private string _imageLink;
public string Image_Link
{
get { return _imageLink; }
set { _imageLink = RssXmlReader.getItemAttribute(value); }
}//////////////////////getItemAttribute//////////////////////
internal static string getItemAttribute(string attributeName)
{
bool bChildFound = false;
string[] str = attributeName.Split('@');
if (str.Length > 1)
{
bChildFound = nav2.MoveToChild(str[0], str[1]);
}
else
{
bChildFound = nav2.MoveToChild(attributeName, "");
}
if (bChildFound)
{
string attribVal = nav2.Value;
nav2.MoveToParent();
return attribVal;
}
return "";
}///////////XML///////////////////////////
- <rss version="2.0" xmlns:g="http://base.google.com/ns/1.0" xmlns:c="http://base.google.com/cns/1.0">
- <channel>
<title>Website RSS</title>
<description>Rss from testing company</description>
- <item>
<g:image_link>http://testingcompany/Photos/793_1623.jpg</g:image_link>
<g:image_link>http://testingcompany/Photos/793_1622.jpg</g:image_link>
</item>
</channel>
</rss>
All Replies
-
Tuesday, April 17, 2012 11:25 AM
I would simply do it like this:
XPathDocument doc = new XPathDocument("input.xml"); XPathNavigator nav = doc.CreateNavigator(); XmlNamespaceManager mgr = new XmlNamespaceManager(nav.NameTable); mgr.AddNamespace("g", "http://base.google.com/ns/1.0"); foreach (XPathNavigator item in doc.CreateNavigator().Select("rss/channel/item")) { foreach (XPathNavigator link in item.Select("g:image_link", mgr)) { Console.WriteLine(link.Value); } }
MVP Data Platform Development My blog
- Proposed As Answer by Hammad_Nasir Wednesday, April 18, 2012 11:33 AM
-
Tuesday, April 17, 2012 12:35 PM
Thanks martin, it works for me but i have one more question,i have some other elements which are single see below
<<g:manufacturer>My man</g:manufacturer><g:product_type>C1</g:product_type>
do i have to iterate them as well like this below, as its single element so i see overhead here.
foreach (XPathNavigator link in item.Select("g:manufacturer", mgr)) { Console.WriteLine(link.Value); }
Also tell me how can i iterate and get values inside children see below. categories have two child and then they have their own child category_code etc.
- Edited by mrhammad Tuesday, April 17, 2012 12:36 PM
-
Tuesday, April 17, 2012 12:50 PM
If you know for sure there will be exactly one child element of a certain kind then you can use SelectSingleNode e.g.
string manufacturer = item.SelectSingleNode("g:manufacturer", mgr).Value;
string productType = item.SelectSingleNode("g:product_type", mgr).Value;
For the more complex sample with the categories, you haven't really explained which data you are looking for, one possible approach might be using the wildcard * e.g.
foreach (XPathNavigator cat in item.Select("Categories/*"))
{
Console.WriteLine("Processing category {0}:", cat.LocalName);
string code = cat.SelectSingleNode("Category_Code").Value;
string desc = cat.SelectSingleNode("Category_Desc").Value;
// now output or store values here
}
MVP Data Platform Development My blog
-
Tuesday, April 17, 2012 12:59 PM
for instance lets say i want to select child of Category2 which are Category_Code & Category_Desc.
-
Tuesday, April 17, 2012 1:23 PM
If you know the child element names when writing the query I would simply use a path expression as in
string code = item.SelectSingleNode("Categories/Category2/Category_Code").Value;
string desc = item.SelectSingleNode("Categories/Category2/Category_Desc").Value;
Use prefixes and an XmlNamespaceManager if namespaces are involved.
MVP Data Platform Development My blog
- Proposed As Answer by Hammad_Nasir Wednesday, April 18, 2012 11:33 AM
-
Wednesday, April 18, 2012 4:56 AM
i am getting error on this
XmlNamespaceManager cns = new XmlNamespaceManager(_nav.NameTable);
cns.AddNamespace("c", "http://base.google.com/ns/1.0");///////////Code///////////
foreach (XPathNavigator item in _doc.CreateNavigator().Select("item/"))
{
///////This code gives me error///////string s = item.SelectSingleNode("c:ref", cns).Value;
}
error
Object reference not set to an instance of an object.
////////////////XML of c:ref like this//////////////////////
<c:ref type="string">1206</c:ref>- Edited by Hammad_Nasir Wednesday, April 18, 2012 5:00 AM
-
Wednesday, April 18, 2012 9:40 AM
Well we need to see the input XML including all namespace declarations to be able to tell what goes wrong, I am afraid showing only the snippet
<c:ref type="string">1206</c:ref>
does not tell us which namespace the 'ref' element is in, whether the namespace URI passed to the XmlNamespaceManager is exactly the same as the one used in the XML.
Franly I would expect the line
_doc.CreateNavigator().Select("item/")
to give an XPath syntax error for "item/".
If you still need help then show us minimal but complete enough samples allowing us to reproduce the error.
MVP Data Platform Development My blog
-
Wednesday, April 18, 2012 11:16 AM
Thats my XML @ Martin
/////////////////////////XML//////////////////
- <rss version="2.0" xmlns:g="http://base.google.com/ns/1.0" xmlns:c="http://base.google.com/cns/1.0">
- <channel>
- <item>
<title>Nikon</title>
<adline>Nikon, V12,</adline>
<guid>260</guid>
<c:reference_number type="string">1206</c:reference_number>
<g:manufacturer>Nikon</g:manufacturer>
<g:product_type>C3806</g:product_type>
<c:umcc_description type="string">COMPARATORS</c:umcc_description>
<g:year>1982</g:year>
<g:model>V12</g:model>
<g:product_status>For Sale</g:product_status>
<g:price>None</g:price>
</item></channel>
</rss>
-
Wednesday, April 18, 2012 11:23 AM
Well I see at least two issues, the latest XML sample you posted has the namespace
http://base.google.com/cns/1.0
whereas in your code sample with the XmlNamespaceManager you have a different namespace
http://base.google.com/ns/1.0
(so instead of "cns" you only have "ns").
That way your code sample tries to find elements in a different namespace.
And of course in your code sample you have the path
c:ref
while your latest XML sample does not have an element of the local name "ref", there is only one of the name "c:reference_number".
MVP Data Platform Development My blog
- Proposed As Answer by Hammad_Nasir Wednesday, April 18, 2012 11:32 AM
-
Wednesday, April 18, 2012 11:32 AM
Very Great @ Martin
You have resolved my issue........................Many Thanks

