簡體   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