Чтение узлов XML

#c# #asp.net #xml #linq-to-xml

#c# #asp.net #xml #linq-to-xml

Вопрос:

У меня есть следующий XML-файл. Я пытаюсь прочитать узел StartDate элемента dept, но не хочу читать узел «StartDate» любого из остальных дочерних элементов, таких как «DeptRoles».

 <dept operationalStatus="active" primaryRole="Admin" depChangeDate="20130420">      
    <startDate type="legal">20130401</startDate>
    <endDate type="legal"></endDate>
    <startDate type="operational">20130320</startDate>
    <endDate type="operational"></endDate>  
    <DeptRoles>         
        <DeptRole name="Other dept" status="active">
            <startDate type="legal">20130401</startDate>
            <endDate type="legal"></endDate>
            <startDate type="operational">20130320</startDate>
            <endDate type="operational"/>
            <isPrimary/>                
        </DeptRole>
    </DeptRoles>
</dept>
  

Это мой код на c #. Этот код также получает элемент DeptRole StartDate, который мне не нужен.

 public static List<organisation> Getorgdata(string data)
    {
        List<organisation> listorgdata = new List<organisation>();
        XmlReader xmlReader = XmlReader.Create(new StringReader(data));
        while (xmlReader.Read())
        {
            if (xmlReader.NodeType == XmlNodeType.Element)
            {
                organisation record = new organisation();
                if (xmlReader.HasAttributes amp;amp; xmlReader.Name == "dept")
                {
                    record.orgOperationalStatus = xmlReader.GetAttribute("operationalStatus");
                    record.orgLegalStatus = xmlReader.GetAttribute("legalStatus");
                }
                else if (xmlReader.Name == "name")
                {
                    record.orgName = xmlReader.ReadElementString("name");
                }

                else if (xmlReader.Name == "startDate" || xmlReader.Name == "endDate")
                {
                    if (xmlReader.GetAttribute("type") == "legal")
                    {
                        record.orgLegalStartDate = xmlReader.ReadElementString("startDate");
                        record.orgLegalEndDate = xmlReader.ReadElementString("endDate");
                    }
                    else if (xmlReader.GetAttribute("type") == "operational")
                    {
                        record.orgOperationalStartDate = xmlReader.ReadElementString("startDate");
                        record.orgOperationalEndDate = xmlReader.ReadElementString("endDate");
                        listorgdata.Add(record);
                    }
                }
            }
        }
        return listorgdata;
    }
  

Ответ №1:

Я бы использовал LINQ для XML (как предлагали другие). Ниже приведен пример кода, который в некоторой степени соответствует вашему опубликованному коду — объяснение кода следует ниже.

 public static List<organisation> Getorgdata(string data)
{

    List<organisation> listorgdata = new List<organisation>();
    XDocument xDoc = XDocument.Parse(data);

    listorgdata = xDoc.Root.Elements("dept")
                  .Select(x => new organisation()
                  {
                      orgOperationalStatus = (string)x.Attribute("operationalStatus"),
                      orgLegalStartDate = (string)x.Elements("startDate")
                                          .Where(x1 => (string)x1.Attribute("type") == "legal")
                                          .First(),
                      orgOperationalStartDate = (string)x.Elements("startDate")
                                                .Where(x1 => (string)x1.Attribute("type") == "operational")
                                                 .First()
                  }).ToList();

     return listorgdata;
}    
  

Первое, что делает приведенный выше код, это загружает XML в XDocument с XDocument.Parse помощью метода.

Затем запрос анализирует XML-документ и возвращает список заполненных organization объектов. Это выглядит примерно так.

  1. Получить все <dept> элементы (и дочерние элементы).
  2. Для каждого <dept> элемента создайте новый экземпляр organisation и присвоите значение атрибута «OperationalStatus» operationalStatus свойству of organisation . (string) Приведение будет корректно обрабатывать ситуацию, когда указанный атрибут отсутствует.
  3. Для получения допустимой даты начала мы выполняем запрос к <startDate> дочерним элементам <dept> элемента, беря первый, у которого атрибут «type» равен «legal».
  4. Для даты начала работы мы выполняем запрос, аналогичный номеру 3, за исключением того, что он ищет «рабочий».
  5. Преобразуйте IEnumerabale<T> результат в список, вызвав метод .ToList() расширения.

Это может быть не самым эффективным, и оно не охватывает все свойства, которые у вас есть в исходном коде, но это должно, по крайней мере, помочь вам двигаться в правильном направлении. Например, если вы хотите получить атрибут «primaryRole», вы бы просто добавили следующую строку в new organisation() блок:

 orgPrimaryRole = (string)x.Attribute("primaryRole"), 
  

Если вам нужны данные, <DeptRoles> вы можете получить их, но это немного сложнее.

Если вы предпочитаете синтаксис запроса синтаксису метода, это будет выглядеть так:

 listorgdata = (from x in xDoc.Root.Elements("dept")
               select new
                   {
                       orgOperationalStatus = (string)x.Attribute("operationalStatus"),
                       orgLegalStartDate = (from x1 in x.Elements("startDate")
                                            where (string)x1.Attribute("type") == "legal"
                                            select (string)x1).First(),
                        orgOperationalStartDate = (from x1 in x.Elements("startDate")
                                                   where (string)x1.Attribute("type") == "operational"
                                                   select (string)x1).First()
                    }).ToList();
  

Ответ №2:

Если я добавлю КАТАЛОГ

 <CATALOG>
<dept operationalStatus="active" primaryRole="Admin" depChangeDate="20130420">      
<startDate type="legal">20130401</startDate>
<endDate type="legal"></endDate>
<startDate type="operational">20130320</startDate>
<endDate type="operational"></endDate>  
<DeptRoles>         
<DeptRole name="Other dept" status="active">
<startDate type="legal">20130401</startDate>
<endDate type="legal"></endDate>
<startDate type="operational">20130320</startDate>
<endDate type="operational"/>
<isPrimary/>                
</DeptRole>
</DeptRoles>
</dept>
</CATALOG>
  

используя System.Xml.Linq; Вы можете получить свой список :

 XElement myXML = XElement.Load(@"C:UsersUserDesktopmyXML.xml");
var deptDescendantsList = (from ep in myXML.Descendants("dept")
                           select ep.Elements("startDate")).ToList();
  

Комментарии:

1. как я узнаю, имеет ли эта дата начала тип legal или operational. не могли бы вы, пожалуйста, изменить этот запрос, если я добавлю deptid=anynumber в узел отдела. как можно использовать этот запрос Lin2Xml, чтобы получить только элемент StartDate, например, deptid =anynumber

Ответ №3:

Я не уверен, как создать запрос, который точно соответствует вашим потребностям. Попробуйте добавить этот запрос к вашим потребностям. http://msdn.microsoft.com/en-us/library/bb387061.aspx содержит некоторую информацию о запросах linq2xml

 XmlReader xmlReader = XmlReader.Create(new StringReader(data));

XDocument d = XDocument.Load(xmlReader);

var startDates = from item in d.Root.Descendants()
                where item.Name == "startDate" amp;amp; item.Parent.Name == "dept" amp;amp; item.Parent.Attribute("deptid").Value == "anynumber"
                select item;

        // iterate over the startDates and do your magic
  

Ответ №4:

Попробуйте это :

var readSpecific = из a в xd.Потомки («отделы»)

                       select new
                      {

                          LegalStartDate = a.Element("dept").Elements("startDate").First(cc => cc.Attribute("type").Value == "legal").Value,
                          LegalEndDate = a.Element("dept").Elements("endDate").First(cc => cc.Attribute("type").Value == "legal").Value,

                          OperationalStartDate = a.Element("dept").Elements("startDate").First(cc => cc.Attribute("type").Value == "operational").Value,
                          OperationEndDate = a.Elements("dept").Elements("endDate").First(cc => cc.Attribute("type").Value == "operational").Value
                       };