2012-07-05 120 views
3

如何解析xml文件?从xml文件获取节点

<?xml version="1.0" encoding="UTF-8"?> 
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> 
<sitemap> 
    <loc>link</loc> 
    <lastmod>2011-08-17T08:23:17+00:00</lastmod> 
</sitemap> 
<sitemap> 
    <loc>link</loc> 
    <lastmod>2011-08-18T08:23:17+00:00</lastmod> 
</sitemap> 
</sitemapindex> 

我是新来的XML,我想这一点,但它似乎不工作:

 XmlDocument xml = new XmlDocument(); //* create an xml document object. 
     xml.Load("sitemap.xml"); 
     XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap"); 
     foreach (XmlNode xn in xnList) 
     { 
      String loc= xn["loc"].InnerText; 
      String lastmod= xn["lastmod"].InnerText; 
     } 
+0

它怎么样?它是否成功加载文件?如果找到两个站点地图元素?它是否读取任何一个sitemap子元素?我假设这些破折号在元素标签不在实际的xml文件中,对吧? – 2012-07-05 16:06:21

+0

xnList没有被填充。(对不起破折号 - 没有破折号) – Andrew 2012-07-05 16:08:11

回答

11

问题是sitemapindex元素定义了一个默认名称空间。您需要在选择节点时指定命名空间,否则将无法找到它们。例如:

XmlDocument xml = new XmlDocument(); 
xml.Load("sitemap.xml"); 
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable); 
manager.AddNamespace("s", "http://www.sitemaps.org/schemas/sitemap/0.9"); 
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager); 

通常来说,使用XmlNameSpaceManager时,你可以离开前缀为空字符串指定您希望该命名空间是默认的命名空间。所以,你会觉得你可以做这样的事情:

// WON'T WORK 
XmlDocument xml = new XmlDocument(); 
xml.Load("sitemap.xml"); 
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable); 
manager.AddNamespace("", "http://www.sitemaps.org/schemas/sitemap/0.9"); //Empty prefix 
XmlNodeList xnList = xml.SelectNodes("/sitemapindex/sitemap", manager); //No prefixes in XPath 

但是,如果你尝试的代码,你会发现,它不会找到任何匹配的节点。原因是在XPath 1.0(这是XmlDocument实现的)中,当没有提供名称空间时,它始终使用空名称空间,而不是默认名称空间。因此,如果您在XmlNamespaceManager中指定默认名称空间,则无关紧要,XPath不会使用它。引述从Official XPath Specification有关段落:

的QName在节点测试扩展成使用 命名空间声明从表达式上下文中的扩展名。这与 中的元素类型名称完全相同 扩展方式除了不使用用xmlns声明的默认名称空间外:如果012xxQName没有前缀,则名称空间URI为空 (这个 与扩展属性名称的方式相同)。如果 QName的前缀在 表达式上下文中没有名称空间声明,则会出错。

因此,当您正在阅读的元素属于某个命名空间时,无法避免将命名空间前缀放入XPath语句中。但是,如果您不想将名称空间URI放入代码中,则可以使用XmlDocument对象返回根元素的URI,在这种情况下,它是您想要的。例如:

XmlDocument xml = new XmlDocument(); 
xml.Load("sitemap.xml"); 
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable); 
manager.AddNamespace("s", xml.DocumentElement.NamespaceURI); //Using xml's properties instead of hard-coded URI 
XmlNodeList xnList = xml.SelectNodes("/s:sitemapindex/s:sitemap", manager); 
+0

你的例子工作正常!谢谢。有没有办法在不指定名称的情况下进入默认名称空间? – Andrew 2012-07-05 16:42:08

+1

@Andrew很高兴帮助!我添加了一些关于命名空间的附加信息给我的答案。 – 2012-07-05 18:30:04

+0

+1很好的信息。很高兴知道。 – SysDragon 2013-07-19 12:28:23

0

网站地图有2个个子节点 “禄” 和 “的lastmod”。您正在访问的节点是“名称”和“网址”。这就是为什么你没有得到任何结果。同样在你的XML文件中,最后一个sitemap标签没有正确关闭,请尝试xn [“loc”]。InnerText,看看你是否得到了预期的结果。

+0

正如OP在他的评论中所说的,问题是没有读取名称和URL,问题是'xnList'是空的。 – 2012-07-05 16:17:46

+0

明白了Steve。我的第二点是XML文件有一个标签'站点地图',它没有关闭。因此,当列表由站点地图标记填充时,由于最后一个站点地图标记而出现错误。 – user1071979 2012-07-05 16:31:36

+0

我很抱歉,但是XML文件是正确的,我修正了上面的示例。上面的SteveDog的例子工作。 – Andrew 2012-07-05 16:40:55

-1

我肯定会使用LINQ to XML而不是基于旧的基于XmlDocument的XML API。你可以使用下面的代码完成你正在寻找的东西。注意,我改变了我试图获得'loc'和'lastmod'值的元素的名称,因为这是你的示例XML('name'和'url'不存在)中的内容:

XElement element = XElement.Parse(XMLFILE); 
     IEnumerable<XElement> list = element.Elements("sitemap"); 
     foreach (XElement e in list) 
     { 
      String LOC= e.Element("loc").Value; 
      String LASTMOD = e.Element("lastmod").Value; 
     }