【问题标题】:Get nodes from xml files从 xml 文件中获取节点
【发布时间】:2018-02-22 00:35:03
【问题描述】:

如何解析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;
        }

【问题讨论】:

  • 它不起作用怎么办?它是否成功加载文件?如果找到两个站点地图元素吗?它是否读取任何一个站点地图子元素?我假设元素标签之前的那些破折号不在实际的 xml 文件中,对吧?
  • xnList 没有被填充。 (对不起破折号 - 没有破折号)

标签: c# xml winforms


【解决方案1】:

问题在于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 声明的默认命名空间:if QName 没有前缀,则命名空间 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);

【讨论】:

  • 您的示例运行良好!谢谢你。有没有办法在不指定名称的情况下进入默认命名空间?
  • @Andrew 很高兴为您提供帮助!我在答案中添加了一些关于命名空间的附加信息。
【解决方案2】:

我肯定会使用 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;
        }

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 正如 OP 在他的评论中所说,问题是没有读取名称和 url,问题是 xnList 是空的。
    • 知道了,史蒂夫。我的第二点是 XML 文件有一个未关闭的标签“站点地图”。因此,当列表由站点地图标签填充时,由于最后一个站点地图标签而出现错误。
    • 我很抱歉,但是 XML 文件是正确的,我修复了上面的示例。 SteveDog 的上述示例有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-14
    • 2019-04-03
    相关资源
    最近更新 更多