2014-02-13 3 views
0

Я пытаюсь проанализировать XML-файл с веб-сайта ООН (http://www.un.org/sc/committees/1267/AQList.xml) с помощью C#.Разбор XML-файла UN в C#

Существует одна проблема, с которой я постоянно сталкиваюсь с этим файлом, и это число дочерних тегов варьируется от одного знака < .INDIVIDUAL.> К другому. Одним из примеров является дочерний тег < .FORTH_NAME.>.

Я пробовал несколько разных подходов, но почему-то я всегда застрял в одной и той же проблеме, и это различное количество дочерних тегов внутри тега < .INDIVIDUAL.>.

То, что я пытаюсь достичь, - собрать все теги и их значения под одним тегом < .INDIVIDUAL.>, А затем вставить только те, которые я хочу в свою базу данных. Если тег отсутствует, например < .FOURTH_NAME.>, То мне нужно вставить только три первых имени в базу данных и пропустить четвертый.

Я попытался с помощью Linq для XML, а вот некоторые примеры:

  XDocument xdoc = XDocument.Load(path); 

      var tags = (from t in xdoc.Descendants("INDIVIDUALS") 
         from a in t.Elements("INDIVIDUAL") 

         select new 
         { 
          Tag = a.Name, 
          val = a.Value 
         }); 

      foreach (var obj in tags) 
      { 
       Console.WriteLine(obj.Tag + " - " + obj.val + "\t"); 

//insert SQL goes here 
      } 

или:

, но это один собирает только непустым теги FOURTH_NAME ...

  var q = (from c in xdoc.Descendants("INDIVIDUAL") 
        from _1 in c.Elements("FIRST_NAME") 
        from _2 in c.Elements("SECOND_NAME") 
        from _3 in c.Elements("THIRD_NAME") 
        from _4 in c.Elements("FOURTH_NAME") 

        where _1 != null && _2 != null && _3 != null && _4 != null 

        select new 
        { 
         _1 = c.Element("FIRST_NAME").Value, 
         _2 = c.Element("SECOND_NAME").Value, 
         _3 = c.Element("THIRD_NAME").Value, 
         _4 = c.Element("FOURTH_NAME").Value 
        }); 

      foreach (var obj in q) 
      { 
       Console.WriteLine("Person: " + obj._1 + " - " + obj._2 + " - " + obj._3 + " - " + obj._4); 
//insert SQL goes here 
      } 

Любые идеи?

ответ

1

Вместо того, чтобы вызывать значение для элемента, рассмотрите возможность использования строкового перевода. LINQ to XML безопасно возвращает null, если элемент не существует. Попробуйте следующее:

var data = XElement.Load(@"http://www.un.org/sc/committees/1267/AQList.xml"); 
var individuals = data.Descendants("INDIVIDUAL") 
    .Select(i => new { 
     First = (string)i.Element("FIRST_NAME"), 
     Middle = (string)i.Element("SECOND_NAME"), 
     Last = (string)i.Element("THIRD_NAME") 
    }); 

Если вы хотите быть более гибкими и получить все поля имени, вы можете сделать что-то вроде следующего. (Я оставлю процесс группировки лиц в качестве дополнительного домашнего задания ;-)

data.Descendants("INDIVIDUAL").Elements() 
    .Where (i =>i.Name.LocalName.EndsWith("_NAME")) 
    .Select(i => new { FieldName= i.Name.LocalName, Value=i.Value}); 
+0

это очень хорошо и полезно. есть ли способ читать теги динамически, без жесткого кодирования этих тегов: first_name, second и т. д.? – Alex

+1

Конечно, вы можете получить имя/значения, используя что-то вроде 'data.Descendants (" INDIVIDUAL "). Elements(). Где (i => i.Name.LocalName.EndsWith (" _ NAME ")). Выберите (i = > new {FieldName = i.Name.LocalName, Value = i.Value}); вы можете также добавить операцию группировки или подвыборку для каждого отдельного пользователя. Это зависит от вас, чтобы обрабатывать синтаксический анализ на основе ваших бизнес-требований. Похоже, что их данные нуждаются в некоторой нормализации.В некоторых случаях вначале есть несколько имен, которые вам нужно разделить. –

+0

Спасибо, Джим, это все, что мне нужно ... – Alex

1

Почему вы не используете XmlSerializer и LINQ вместо?

Как объяснен в this ответе, создавать свои классы, вставив в новой CS файл:

menu EDIT > Paste Special > Paste XML As Classes.

Затем захватить ваши данные так же легко, следующим образом:

var serializer = new XmlSerializer(typeof (CONSOLIDATED_LIST)); 
using (FileStream fileStream = File.OpenRead(@"..\..\aqlist.xml")) 
{ 
    var list = serializer.Deserialize(fileStream) as CONSOLIDATED_LIST; 
    if (list != null) 
    { 
     var enumerable = list.INDIVIDUALS.Select(s => new 
     { 
      FirstName = s.FIRST_NAME, 
      SecondName = s.SECOND_NAME, 
      ThirdName = s.THIRD_NAME, 
      FourthName = s.FOURTH_NAME 
     }); 
    } 
} 

enter image description here

Затем вы можете указать любой предикат, который лучше соответствует вашим потребностям.

Переход этот путь будет сэкономить массу времени и менее подвержены ошибкам, нет необходимости использовать строки для доступа к полям, сильный ввод и т.д. ...