繁体   English   中英

使用xPath C#无法从XML获取值

[英]Unable to get values from XML using xPath C#

我有两个XML文件,我可以通过c#中的xPath从第一个XML获取数据,这里:

<CONSOLIDATED_LIST xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                    xsi:noNamespaceSchemaLocation="https://www.example/acb.xsd" 
                    dateGenerated="2018-04-19T19:18:41.129-04:00">
  <INDIVIDUALS>
    <INDIVIDUAL>
      <DATAID>2975591</DATAID>
      <VERSIONNUM>1</VERSIONNUM>
      <FIRST_NAME>ABC</FIRST_NAME>
      <SECOND_NAME>XYZ</SECOND_NAME>      
      <INDIVIDUAL_ALIAS>
        <QUALITY>Good</QUALITY>
        <ALIAS_NAME>abcd</ALIAS_NAME>
      </INDIVIDUAL_ALIAS>
      <INDIVIDUAL_ALIAS>
        <QUALITY>Bad</QUALITY>
        <ALIAS_NAME>ylmn</ALIAS_NAME>
      </INDIVIDUAL_ALIAS>      
    </INDIVIDUAL>
  </INDIVIDUALS>
 </CONSOLIDATED_LIST>

我获取数据的方式,还请参见代码中的注释。

 var xml = DownloadString(link); //link refers to XML file on web
            e = XElement.Parse(xml);

            //parentNodeForPerson = "INDIVIDUAL" for above and "sdnEntry" for below;
            var lstIndividuals = e.Descendants(parentNodeForPerson);

            Data _individualData;
            List<Data> individualList = new List<Data>();

            foreach (var individual in lstIndividuals)
            {
                _individualData = new Data();
                //personParentValue1 for above is FIRST_NAME and below is firstName
                _individualData.First_Name = individual.Descendants(personParentValue1)
                    .Any() == true ? individual.Descendants(personParentValue1).First().Value : "";
                //personParentValue2 for above is SECOND_NAME and below is lastName
                _individualData.Last_Name = individual.Descendants(personParentValue2)
                    .Any() == true ? individual.Descendants(personParentValue2).First().Value : "";
                //childNodeForPersonfor above is INDIVIDUAL_ALIAS and below is aka
                var lstIndvidualAlias = individual.Descendants(childNodeForPerson);
                _individualData.Alias = new List<string>();

                foreach (var alias in lstIndvidualAlias)
                {
                    //personChildValue1 for above is ALIAS_NAME and below is lastName & fisrtName
                    if (!String.IsNullOrWhiteSpace(alias.Descendants(personChildValue1).First().Value))
                    {
                        _individualData.Alias.Add(alias.Descendants(personChildValue1)
                            .Any() == true ? alias.Descendants(personChildValue1).First().Value : "");

                    }

                }
                individualList.Add(_individualData);
            }

这是我没有获取数据的XML

<List xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns="http://tempuri.org/List.xsd">
  <publshInformation>
    <Publish_Date>04/18/2018</Publish_Date>
    <Record_Count>6299</Record_Count>
  </publshInformation>
  <sdnEntry>

    <lastName>ABCD</lastName>
    <fisrtName>XYS</fisrtName>
    <akaList>
      <aka>        
        <category>strong</category>
        <lastName>ABCDT</lastName>
        <fisrtName>XYS</fisrtName>
      </aka>
      <aka>        
        <category>Weak</category>
        <lastName>AssDT</lastName>
        <fisrtName>XYsS</fisrtName>
      </aka>
    </akaList>    
  </sdnEntry>
  </List>

编辑:

资料类别

public class Data
    {
        public string Last_Name { get; set; }
        public string First_Name { get;  set; }       
        public List<string> Alias { get; set; }

    }

我尝试了您的xml。 我已经使用了xml解串器,并且在我看来效果很好。 请检查以下代码:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Reflection;
using System.Xml.Serialization;
using XML1;
using XML2;

namespace ConsoleApplication1
{
    public class Program
    {
        private static void Main(string[] args)
        {
            var list1 = Deserialize<CONSOLIDATED_LIST>(@"CONSOLIDATED_LIST.xml"); // pass the path to your xml here
            var list2 = Deserialize<List>(@"LIST.xml");
        }

        public static T Deserialize<T>(string path)
        {
            T obj;            
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            var reader = new StreamReader(path);
            obj = (T)serializer.Deserialize(reader);
            reader.Close();
            return obj;
        }
    }
}

namespace XML1
{
    [XmlRoot(ElementName = "INDIVIDUAL_ALIAS")]
    public class INDIVIDUAL_ALIAS
    {
        [XmlElement(ElementName = "QUALITY")]
        public string QUALITY { get; set; }
        [XmlElement(ElementName = "ALIAS_NAME")]
        public string ALIAS_NAME { get; set; }
    }

    [XmlRoot(ElementName = "INDIVIDUAL")]
    public class INDIVIDUAL
    {
        [XmlElement(ElementName = "DATAID")]
        public string DATAID { get; set; }
        [XmlElement(ElementName = "VERSIONNUM")]
        public string VERSIONNUM { get; set; }
        [XmlElement(ElementName = "FIRST_NAME")]
        public string FIRST_NAME { get; set; }
        [XmlElement(ElementName = "SECOND_NAME")]
        public string SECOND_NAME { get; set; }
        [XmlElement(ElementName = "INDIVIDUAL_ALIAS")]
        public List<INDIVIDUAL_ALIAS> INDIVIDUAL_ALIAS { get; set; }
    }

    [XmlRoot(ElementName = "INDIVIDUALS")]
    public class INDIVIDUALS
    {
        [XmlElement(ElementName = "INDIVIDUAL")]
        public INDIVIDUAL INDIVIDUAL { get; set; }
    }

    [XmlRoot(ElementName = "CONSOLIDATED_LIST")]
    public class CONSOLIDATED_LIST
    {
        [XmlElement(ElementName = "INDIVIDUALS")]
        public INDIVIDUALS INDIVIDUALS { get; set; }
        [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xsi { get; set; }
        [XmlAttribute(AttributeName = "noNamespaceSchemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
        public string NoNamespaceSchemaLocation { get; set; }
        [XmlAttribute(AttributeName = "dateGenerated")]
        public string DateGenerated { get; set; }
    }

}

namespace XML2
{
    [XmlRoot(ElementName = "publshInformation", Namespace = "http://tempuri.org/List.xsd")]
    public class PublshInformation
    {
        [XmlElement(ElementName = "Publish_Date", Namespace = "http://tempuri.org/List.xsd")]
        public string Publish_Date { get; set; }
        [XmlElement(ElementName = "Record_Count", Namespace = "http://tempuri.org/List.xsd")]
        public string Record_Count { get; set; }
    }

    [XmlRoot(ElementName = "aka", Namespace = "http://tempuri.org/List.xsd")]
    public class Aka
    {
        [XmlElement(ElementName = "category", Namespace = "http://tempuri.org/List.xsd")]
        public string Category { get; set; }
        [XmlElement(ElementName = "lastName", Namespace = "http://tempuri.org/List.xsd")]
        public string LastName { get; set; }
        [XmlElement(ElementName = "fisrtName", Namespace = "http://tempuri.org/List.xsd")]
        public string FisrtName { get; set; }
    }

    [XmlRoot(ElementName = "akaList", Namespace = "http://tempuri.org/List.xsd")]
    public class AkaList
    {
        [XmlElement(ElementName = "aka", Namespace = "http://tempuri.org/List.xsd")]
        public List<Aka> Aka { get; set; }
    }

    [XmlRoot(ElementName = "sdnEntry", Namespace = "http://tempuri.org/List.xsd")]
    public class SdnEntry
    {
        [XmlElement(ElementName = "lastName", Namespace = "http://tempuri.org/List.xsd")]
        public string LastName { get; set; }
        [XmlElement(ElementName = "fisrtName", Namespace = "http://tempuri.org/List.xsd")]
        public string FisrtName { get; set; }
        [XmlElement(ElementName = "akaList", Namespace = "http://tempuri.org/List.xsd")]
        public AkaList AkaList { get; set; }
    }

    [XmlRoot(ElementName = "List", Namespace = "http://tempuri.org/List.xsd")]
    public class List
    {
        [XmlElement(ElementName = "publshInformation", Namespace = "http://tempuri.org/List.xsd")]
        public PublshInformation PublshInformation { get; set; }
        [XmlElement(ElementName = "sdnEntry", Namespace = "http://tempuri.org/List.xsd")]
        public SdnEntry SdnEntry { get; set; }
        [XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
        public string Xsi { get; set; }
        [XmlAttribute(AttributeName = "xmlns")]
        public string Xmlns { get; set; }
    }
}

我个人更喜欢xml反序列化器。 这将是容易和可维护的。 您的基础代码将保持不变,并且反序列化可以基于xml中的T​​ype T完成

是的,这很正常,并且取决于名称空间。 只需编辑您的LINQ查询,然后从您所使用的查询开始:

var lstIndividuals = e.Descendants(parentNodeForPerson);

对此:

var lstIndividuals = e.Descendants().Where(f => f.Name.LocalName.ToString() == parentNodeForPerson); 

它将起作用。


长期解释

当按名称检索元素时,以上解决方案基本上会忽略所有名称空间信息。 事实是,在第一个XML中,您具有:

<CONSOLIDATED_LIST xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:noNamespaceSchemaLocation="https://www.example/acb.xsd" 
    dateGenerated="2018-04-19T19:18:41.129-04:00">

在第二个中,我们发现

<List xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns="http://tempuri.org/List.xsd">

第二个XML有两个定义的名称空间,这使您的LINQ查询摆脱了麻烦。 实际上,如果您只是从第二个XML中删除了它

xmlns="http://tempuri.org/List.xsd"

您的代码可以正常运行而无需任何更改。

首先,您可以阅读以下答案: XML中的“ xmlns”是什么意思? 尤其是这个 简而言之,例如,当您组合来自不同来源的XML并获得具有相同名称的元素时,名称空间可能会很有用:通过在名称空间前面添加名称相同的元素,可以将它们视为不同的元素:

<namespaceA:elementName>blah     </namespaceA:elementName>
<namespaceB:elementName>blah blah</namespaceB:elementName>

在您的XML中,您有两个名称空间,但是在寻找Descendants您没有指定元素所属的名称空间。 另一个解决方案(也许比上面的快速解决方案更健壮)是指定元素名称所属的名称空间,例如,像本问题中的OP那样,使用XName.Get :在您的情况下,您将获得这样的第二个XML:

var lstIndividuals = e.Descendants(XName.Get(parentNodeForPerson, "http://tempuri.org/List.xsd"));

之所以有效,是因为指定的URI( http://tempuri.org/List.xsd )是您声明的默认名称空间之一:

 xmlns="http://tempuri.org/List.xsd"

并且,由于您的元素没有任何前缀,因此它是元素所属的名称空间; 如果它们属于您定义的另一个命名空间(即xsi ,则其名称将为例如xsi:sdnEntry

当然,由于您的第一个XML声明中没有默认名称空间,而只有xsi名称空间(它引用了另一个URI),因此您需要将其URI传递给XName.Get并修改您的代码。 换句话说,您应该使URL参数化并将其传递给您的方法,而不是像我一样对其进行硬编码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM