如何仅处理某些 XML 节点
本文关键字:XML 节点 何仅 处理 | 更新日期: 2023-09-27 18:25:47
这是我的XML代码段(它有一个根元素(。
<ItemAttributes>
<Author>Ellen Galinsky</Author>
<Binding>Paperback</Binding>
<Brand>Harper Paperbacks</Brand>
<EAN>9780061732324</EAN>
<EANList>
<EANListElement>9780061732324</EANListElement>
</EANList>
<Edition>1</Edition>
<Feature>ISBN13: 9780061732324</Feature>
<Feature>Condition: New</Feature>
<Feature>Notes: BRAND NEW FROM PUBLISHER! 100% Satisfaction Guarantee. Tracking provided on most orders. Buy with Confidence! Millions of books sold!</Feature>
<ISBN>006173232X</ISBN>
<IsEligibleForTradeIn>1</IsEligibleForTradeIn>
<ItemDimensions>
<Height Units="hundredths-inches">112</Height>
<Length Units="hundredths-inches">904</Length>
<Weight Units="hundredths-pounds">98</Weight>
<Width Units="hundredths-inches">602</Width>
</ItemDimensions>
<Label>William Morrow Paperbacks</Label>
<ListPrice>
<Amount>1699</Amount>
<CurrencyCode>USD</CurrencyCode>
<FormattedPrice>$16.99</FormattedPrice>
</ListPrice>
<Manufacturer>William Morrow Paperbacks</Manufacturer>
<MPN>006173232X</MPN>
<NumberOfItems>1</NumberOfItems>
<NumberOfPages>400</NumberOfPages>
<PackageDimensions>
<Height Units="hundredths-inches">120</Height>
<Length Units="hundredths-inches">880</Length>
<Weight Units="hundredths-pounds">95</Weight>
<Width Units="hundredths-inches">590</Width>
</PackageDimensions>
<PartNumber>006173232X</PartNumber>
<ProductGroup>Book</ProductGroup>
<ProductTypeName>ABIS_BOOK</ProductTypeName>
<PublicationDate>2010-04-20</PublicationDate>
<Publisher>William Morrow Paperbacks</Publisher>
<ReleaseDate>2010-04-20</ReleaseDate>
<SKU>mon0000013657</SKU>
<Studio>William Morrow Paperbacks</Studio>
<Title>Mind in the Making: The Seven Essential Life Skills Every Child Needs</Title>
</ItemAttributes>
有多个"项目属性"节点,每个节点都有不同的"产品组"节点。 我只想要第一个"项目属性",其中"产品组"="书:">
这是我的 C# 代码:
XPathDocument doc = new XPathDocument(sr);
XPathNavigator nav = doc.CreateNavigator();
// Compile a standard XPath expression
XPathExpression expr;
expr = nav.Compile("//ItemAttributes[contains(ProductGroup, 'Book')]");
XPathNodeIterator iterator = nav.Select(expr);
// Iterate on the node set
try {
int x = iterator.Count; // <----------- count = 0
while (iterator.MoveNext()) { // <----------- finds nothing!
XPathNavigator nav2 = iterator.Current.Clone();
listBox1.Items.Add("price: " + nav2.Value);
}
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
我知道我的代码不正确,但我不明白为什么迭代器。计数为零!
使用System.Xml.Linq
XDocument xdoc = XDocument.Load(new StringReader(xmlstr));
var foundNode = xdoc
.Descendants("ItemAttributes")
.Where(node => node.Element("ProductGroup").Value == "Book")
.First();
var price = foundNode.Element("ListPrice").Element("FormattedPrice").Value;
--编辑--
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
string xmlstr = @"
<root>
<ItemAttributes>
<Author>Ellen Galinsky</Author>
<Binding>Paperback</Binding>
<Brand>Harper Paperbacks</Brand>
<EAN>9780061732324</EAN>
<EANList>
<EANListElement>9780061732324</EANListElement>
</EANList><Edition>1</Edition>
<Feature>ISBN13: 9780061732324</Feature>
<Feature>Condition: New</Feature>
<Feature>Notes: BRAND NEW FROM PUBLISHER! 100% Satisfaction Guarantee. Tracking provided on most orders. Buy with Confidence! Millions of books sold!</Feature>
<ISBN>006173232X</ISBN>
<IsEligibleForTradeIn>1</IsEligibleForTradeIn>
<ItemDimensions>
<Height Units=""hundredths-inches"">112</Height>
<Length Units=""hundredths-inches"">904</Length>
<Weight Units=""hundredths-pounds"">98</Weight>
<Width Units=""hundredths-inches"">602</Width>
</ItemDimensions>
<Label>William Morrow Paperbacks</Label>
<ListPrice>
<Amount>1699</Amount>
<CurrencyCode>USD</CurrencyCode>
<FormattedPrice>$16.99</FormattedPrice>
</ListPrice>
<Manufacturer>William Morrow Paperbacks</Manufacturer>
<MPN>006173232X</MPN>
<NumberOfItems>1</NumberOfItems>
<NumberOfPages>400</NumberOfPages>
<PackageDimensions>
<Height Units=""hundredths-inches"">120</Height>
<Length Units=""hundredths-inches"">880</Length>
<Weight Units=""hundredths-pounds"">95</Weight>
<Width Units=""hundredths-inches"">590</Width>
</PackageDimensions>
<PartNumber>006173232X</PartNumber>
<ProductGroup>Book</ProductGroup>
<ProductTypeName>ABIS_BOOK</ProductTypeName>
<PublicationDate>2010-04-20</PublicationDate>
<Publisher>William Morrow Paperbacks</Publisher>
<ReleaseDate>2010-04-20</ReleaseDate>
<SKU>mon0000013657</SKU>
<Studio>William Morrow Paperbacks</Studio>
<Title>Mind in the Making: The Seven Essential Life Skills Every Child Needs</Title>
</ItemAttributes>
</root>
";
XDocument xdoc = XDocument.Load(new StringReader(xmlstr));
var foundNode = xdoc
.Descendants("ItemAttributes")
.Where(node => node.Element("ProductGroup").Value == "Book")
.First();
Console.WriteLine(foundNode.Element("ListPrice").Element("FormattedPrice").Value);
Console.ReadLine();
}
}
}
--编辑2--
XDocument xdoc = XDocument.Load("http://ecs.amazonaws.com/onca/xml?AWSAccessKeyId=AKIAIAAFYAPOR6SX5GOA&AssociateTag=pragbook-20&IdType=ISBN&ItemId=9780061732324&MerchantId=All&Operation=ItemLookup&ResponseGroup=Medium&SearchIndex=Books&Service=AWSECommerceService&Timestamp=2012-02-26T20%3A18%3A37Z&Version=2011-08-01&Signature=r7yE7BQI44CqWZAiK%2FWumF3N4iutOj3re9wZtESOaKs%3D");
XNamespace ns = XNamespace.Get("http://webservices.amazon.com/AWSECommerceService/2011-08-01");
var foundNode = xdoc
.Descendants(ns+"ItemAttributes")
.Where(node => node.Element(ns+"ProductGroup").Value == "Book")
.First();
Console.WriteLine(foundNode.Element(ns+"ListPrice").Element(ns+"FormattedPrice").Value);
Console.ReadLine();
我会使用 XPath 和 XmlDocument
来处理这个问题。
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(myXMLString);
XmlNodeList nodeList = xDoc.SelectNodes("//ItemAttributes[./ProductGroup[text()='Book']]");
foreach (XmlNode node in nodeList)
{
//Do anything with node.Value;
}
我没有尝试过你的代码,但从我所看到的你的 XPath 表达式不正确。我已经分解了我在下面写的表达。
它读作
//ItemAttributes #look for all nodes named ItemAttributes
[
./ProductGroup #with a child node called ProductGroup
[
text()='Book' #that has the string 'Book' as the text
]
]
你说你的XML是一个片段。 我冒昧地猜测它包含在将默认命名空间前缀绑定到非平凡 URI 的元素中,这就是为什么您没有从迭代器中获得任何结果的原因。
您的代码对我有用,上面给出的XML文档。 我运行了代码并从迭代器中获取了一个元素。 然后,我拿起您的 XML 文档并将其包装在一个根元素中,该根元素将默认命名空间前缀绑定到一个虚构但非平凡的 URI:
<SomeRootElement xmlns="http://schemas.blahblahblah.com/example">
<ItemAttributes>
<!-- rest of your document omitted -->
</ItemAttributes>
</SomeRootElement>
然后我从迭代器中没有得到任何结果。
然后,我创建了一个 XmlNamespaceManager,它将前缀(我选择了 pfx
(映射到上面使用的命名空间 URI:
XmlNamespaceManager mgr = new XmlNamespaceManager(new NameTable());
mgr.AddNamespace("pfx", "http://schemas.blahblahblah.com/example");
然后,我将此命名空间管理器设置为 XPath 表达式的命名空间上下文,并将前缀pfx
添加到 XPath 表达式中的名称:
XPathExpression expr;
expr = nav.Compile("//pfx:ItemAttributes[contains(pfx:ProductGroup, 'Book')]");
expr.SetContext(mgr);
XPathNodeIterator iterator = nav.Select(expr);
然后,正如预期的那样,我从迭代器中取出了一个元素。
XPath 对于命名空间可能有点有趣。 我尝试将空前缀""
绑定到 URI,以便我可以未经修改地使用您的 XPath 表达式,但这不起作用。 这是我以前在 XPath 中发现的一件事:始终将命名空间 URI 绑定到 XPath 的前缀,即使原始 XML 文档绑定了默认命名空间前缀。 XPath 中不带前缀的名称似乎始终位于"null"命名空间中。
我还没有真正研究过如何在 .NET 中使用 XPath 将命名空间前缀映射到 URI,并且可能比我在快速谷歌搜索和阅读 MSDN 后拼凑起来的方法更好。
编辑:我回答的目的是解释为什么你的代码使用XPath不起作用。 你不明白为什么你没有从迭代器中获得任何结果。 我怀疑你没有给我完整的XML文档,并且在你没有与我们分享的文档部分奠定了答案。
最终,我相信您的原始代码由于 XML 命名空间而不起作用。 在我撰写此编辑时,我只能从您使用 L.B 的评论线程中的 URL 中收到"请求已过期"错误,因此我无法再使用您正在使用的相同类型的数据进行测试。 但是,此错误请求的开头如下所示:
<?xml version="1.0"?>
<ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2011-08-01/">
xmlns
属性将元素以及其中包含的每个元素放入命名空间中。 每个命名空间都由一个 URI 标识,URI 和元素名称一起标识该元素。
可能是成功的请求可能具有相同的属性。 但是,L.B.的答案使用了不同的命名空间,所以我不能确定。 对于此编辑的其余部分,我必须假设成功的请求确实包含与不成功的请求相同的命名空间。
由于此命名空间,元素<ItemAttributes>
在此 XML 中
<ItemLookupResponse xmlns="http://ecs.amazonaws.com/doc/2011-08-01/">
<ItemAttributes />
</ItemLookupResponse>
并在此 XML 中
<ItemAttributes />
不一样。 第一个位于 http://ecs.amazonaws.com/doc/2011-08-01/
命名空间中,而第二个位于由空字符串标识的命名空间中。 此空命名空间是默认命名空间(如果尚未以任何其他方式设置(。
由于两个ItemAttributes
元素具有不同的命名空间,因此它们并不相同。
除了使用 xmlns="..."
更改元素的命名空间外,您还可以将前缀关联(或绑定(到命名空间。 这是通过使用 xmlns:prefix="some-uri"
等属性在 xmlns
属性中指定要与命名空间关联的前缀来完成的。 然后将此前缀放入 XML 元素的本地名称之前,例如 <prefix:SomeElement ... />
。 这会将 SomeElement
元素放在与 URI some-uri
关联的命名空间中。
由于元素由本地名称和命名空间 URI 标识,因此以下两个 XML 片段是相等的,即使一个使用前缀而另一个不使用前缀也是如此:
<ItemLookupResponse xmlns="http://ecs.amazonaws.com/doc/2011-08-01/">
<ItemAttributes />
</ItemLookupResponse>
<ecs:ItemLookupResponse xmlns:ecs="http://ecs.amazonaws.com/doc/2011-08-01/">
<ecs:ItemAttributes />
</ecs:ItemLookupResponse>
现在我们转向 XPath 和命名空间。 您的 XPath 表达式是
//ItemAttributes[contains(ProductGroup, 'Book')]
XPath 的一个恼火是,您不能像使用 XML 那样更改不使用前缀的命名空间。 因此,上面ItemAttributes
和ProductGroup
的名称始终位于"空"命名空间中。 此 XPath 表达式与 XML 文档中的任何内容都不匹配,因为"空"命名空间中没有具有本地名称ItemAttributes
元素,更不用说任何具有包含文本Book
的ProductGroup
子元素的元素了。
但是,对于大多数(如果不是全部(XPath API,有一些方法可以将前缀绑定到命名空间。 我所做的是展示一种在 .NET 中使用 XPath 执行此操作的方法。 我将前缀pfx
(我可以选择任何我想要的前缀(与我在上面示例中使用的 URI 相关联。 您将使用与我虚构的示例不同的 URI。 然后,您可以使用 XPath 表达式
//pfx:ItemAttributes[contains(pfx:ProductGroup, 'Book')]
查找相关元素,因为存在名称为 ItemAttributes
和命名空间http://ecs.amazonaws.com/doc/2011-08-01/
的元素,并且其中至少有一个包含名称为 ProductGroup
的子元素位于同一命名空间中,并且文本内容Book
。