这是我的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>
有多个“ItemAttributes”节点,每个节点都有一个不同的“ProductGroup”节点。我只想要第一个“ItemAttribute”,其中“ProductGroup”=“book:”
这是我的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);
}
我知道我的代码不正确,但我不明白为什么iterator.Count为零!
答案 0 :(得分:4)
使用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();
}
}
}
<强> - EDIT2 - 强>
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();
答案 1 :(得分:0)
我会使用带有XmlDocument
的XPath来处理这个问题。
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
]
]
答案 2 :(得分:0)
您说您的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,并且可能有更好的方法来实现它,而不是我在快速搜索和阅读MSDN后拼凑在一起的方法。 / p>
编辑:我的回答的目的是解释为什么使用XPath的代码不起作用。你不明白为什么你没有从迭代器中得到任何结果。我怀疑你没有给我完整的XML文档,而且你没有与我们分享的文档部分给出了答案。
最终,我认为您的原始代码因XML namespaces而无效。当我编写此编辑时,我只能从L.B的评论主题中的URL中获得“请求已过期”错误,因此我无法再使用您正在使用的相同类型的数据进行测试。但是,此错误请求的确如下所示:
<?xml version="1.0"?>
<ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2011-08-01/">
xmlns
属性将元素及其中包含的每个元素放入名称空间。每个名称空间由URI标识,URI和元素名称一起标识该元素。
成功的请求可能具有相同的属性。但是,L.B。的答案使用了不同的命名空间,所以我无法确定。对于本次编辑的其余部分,我将不得不假设一个成功的请求确实包含与不成功的命名空间相同的命名空间。
由于此命名空间,此XML中的元素<ItemAttributes>
<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
等属性在xmlns:prefix="some-uri"
属性中指定要与名称空间关联的前缀来完成的。然后将此前缀放在本地名称之前的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
的元素,更不用说包含文本ProductGroup
的{{1}}子元素。
但是,对于大多数(如果不是全部)XPath API,有一些方法可以将前缀绑定到名称空间。我所做的是用.NET中的XPath显示一种方法。我将前缀Book
(我可以选择我想要的任何前缀)与我在上面的示例中使用的URI相关联。您将使用不同的URI来构建示例。然后,您可以使用XPath表达式
pfx
查找相关元素,因为存在名称为//pfx:ItemAttributes[contains(pfx:ProductGroup, 'Book')]
且名称空间为ItemAttributes
的元素,并且其中至少有一个元素包含名称为http://ecs.amazonaws.com/doc/2011-08-01/
的子元素相同的命名空间和文本内容ProductGroup
。