为什么这个程序不能访问子节点?

时间:2015-06-19 15:56:08

标签: c# xml xmldocument

这里获取XML文档和各个节点,并将节点插入字典中。

//create the xml document obj
XmlDocument inputXMLDoc = new XmlDocument();
fileref.isValid = false;
//load the xml document
#region
try
{
    inputXMLDoc.XmlResolver = null;
    inputXMLDoc.Load( strfile );//load the xml file
    string input = inputXMLDoc.OuterXml;//get the string

    Console.WriteLine( "success,loaded XML" );
    logger.Log( "loaded xml:" + strfile );


    fileref.importList = new Dictionary<string, XmlNode>();

    nodeNames = new List<string> { "OrderId", "CustomerId", "CustomerName", "Addresses", "OrderStatus", "DateOrdered", "PaymentTime", "IncludeVAT", "OrderTotalIncVat", "OrderTotalVat", "Currency", "TypeOfSaleId" };

    try
    {
        int i = 0;
        foreach( string name in nodeNames )
        {
            Console.WriteLine( "Adding xml node " + name );

            if( inputXMLDoc.GetElementsByTagName( name ) != null )
            {
                XmlNodeList xlist = inputXMLDoc.GetElementsByTagName( name );

                foreach( XmlNode node in xlist )
                {
                    fileref.importList.Add( name, node );
                    //add individual node within nodelist
                    Console.WriteLine( name );

                }
            } //add specified node from XML doc
            else
            {
                nodeNames.RemoveAt( i );
            }
            i++;
        }
    }
}

稍后,访问节点以将信息保存到Web服务。但是,具有子节点的节点不会以这种方式显示。

 Invoices.Address address = new Invoices.Address();

 XmlNodeList oNodeList = fileref.importList["Addresses"].SelectNodes("/Delivery/Street");
 foreach (XmlNode xn in oNodeList)
 {
     address.Street = xn.InnerText;
 }

示例XML文档

<?xml version="1.0" encoding="utf-8"?>
<InvoiceOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <OrderId xmlns="http://24sevenOffice.com/webservices">35</OrderId>
  <CustomerId xmlns="http://24sevenOffice.com/webservices">21</CustomerId>
  <CustomerName xmlns="http://24sevenOffice.com/webservices">James Bond</CustomerName>
  <Addresses xmlns="http://24sevenOffice.com/webservices">
    <Delivery>
      <Street>11 Shewell Walk</Street>
      <State />
      <PostalCode>CO1 1WG</PostalCode>
      <PostalArea>Essex</PostalArea>
      <Name />
      <City>Colchester</City>
      <Country>UK</Country>
    </Delivery>
    <Invoice>
      <Street>10 Shewell Walk</Street>
      <State />
      <PostalCode>CO1 1WG</PostalCode>
      <PostalArea>Essex</PostalArea>
      <Name />
      <City>Colchester</City>
      <Country>UK</Country>
    </Invoice>
  </Addresses>
  <OrderStatus xmlns="http://24sevenOffice.com/webservices">Offer</OrderStatus>
  <DateOrdered xmlns="http://24sevenOffice.com/webservices">2015-06-15T14:00:00Z</DateOrdered>
  <PaymentTime xmlns="http://24sevenOffice.com/webservices">14</PaymentTime>
  <IncludeVAT xsi:nil="true" xmlns="http://24sevenOffice.com/webservices" />
  <OrderTotalIncVat xmlns="http://24sevenOffice.com/webservices">480.0000</OrderTotalIncVat>
  <OrderTotalVat xmlns="http://24sevenOffice.com/webservices">80.0000</OrderTotalVat>
  <Currency xmlns="http://24sevenOffice.com/webservices">
    <Symbol>LOCAL</Symbol>
  </Currency>
  <TypeOfSaleId xmlns="http://24sevenOffice.com/webservices">-100</TypeOfSaleId>
  <InvoiceRows xmlns="http://24sevenOffice.com/webservices">
    <InvoiceRow>
      <ProductId>18</ProductId>
      <RowId>4665754</RowId>
      <Price>400.0000</Price>
      <Name>17" Laptop Screen</Name>
      <DiscountRate>0.0000</DiscountRate>
      <Quantity>7.0000</Quantity>
      <Cost>0.0000</Cost>
      <InPrice>0.0000</InPrice>
    </InvoiceRow>
  </InvoiceRows>
</InvoiceOrder>

2 个答案:

答案 0 :(得分:1)

您遇到的问题是名称空间。如果为每个元素指定命名空间,那么它似乎有效。我通过一些谷歌搜索和一些实验得出了这个结论,所以我的解释可能不会被发现,所以我建议你自己进一步研究这个问题,以便正确理解它。

此代码可以使用:

XmlNamespaceManager nsmgr = new XmlNamespaceManager(inputXMLDoc.NameTable);
nsmgr.AddNamespace("ns", "http://24sevenOffice.com/webservices");
var oNodeList = importList["Addresses"].SelectNodes("//ns:Delivery/ns:Street",nsmgr);

原因是(我认为)在XML文档中,您为元素(xmlns="http://24sevenOffice.com/webservices")指定了默认命名空间,而在xpath中,您没有指定相同的命名空间。在我的代码中,我创建了一个带有该命名空间的命名空间管理器,并将其作为两个元素的前缀,它现在认为它们与文档中具有这些命名空间的元素相匹配。

答案 1 :(得分:1)

您的代码无法正常工作的原因可能是您忽略了您正在寻找的元素的命名空间。关于如何做到这一点有很多问题,例如this one

那就是说,XmlDocument是一个蹩脚的旧API,而较新的LINQ to XML是一个巨大的进步 - 我建议你研究一下。

我也不确定字典是否会为这么少的元素拉扯它的重量。您可以直接从XML查询所需内容。例如,要将所有字段作为类型化值:

var doc = XDocument.Parse(strfile);      
var order = doc.Elements("InvoiceOrder").Single();

XNamespace ns = "http://24sevenOffice.com/webservices";

var orderId = (int)order.Element(ns + "OrderId");
var customerId = (int)order.Element(ns + "CustomerId");
var customerName = (string)order.Element(ns + "CustomerName");
var orderStatus = (string)order.Element(ns + "OrderStatus");
var dateOrdered = (DateTime)order.Element(ns + "DateOrdered");
var paymentTime = (int)order.Element(ns + "PaymentTime");
var totalIncVat = (decimal)order.Element(ns + "OrderTotalIncVat");
var totalVat = (decimal)order.Element(ns + "OrderTotalVat");
var currency = (string)order.Elements(ns + "Currency").Elements(ns + "Symbol").SingleOrDefault();
var typeOfSaleId = (int)order.Element(ns + "TypeOfSaleId");

您可以使用类似的技巧将地址映射到强类型的Address类:

var deliveryAddress = order.Elements(ns + "Addresses")
    .Elements(ns + "Delivery")
    .Select(e => new Invoice.Address
    {
        Street = (string)e.Element(ns + "Street"),
        // ....
    })
    .Single();