Улучшение получения данных из XML-файла - PullRequest
1 голос
/ 14 октября 2011

У меня есть XML-файл, подобный этому:

   <Document>
       <Tests Count="4">
          <Test>
             <Name>test with a</Name>
             <Type>VI test</Type>
             <Result>Pass</Result>
          </Test>
          <Test>
             <Name>test plot</Name>
             <Type>Curve test</Type>
             <Result>Fail</Result>
          </Test>
          <Test>
             <Name>test fixture</Name>
             <Type>Leakage test</Type>
             <Result>Pass</Result>
          </Test>      
          <Test>
             <Name>test fixture</Name>
             <Type>Leakage test</Type>
          </Test>             
        </Tests>
   </Document>

Я создал класс для каждого теста:

class TestGroup
{
    public string TestName { get; set; }
    public string TestType { get; set; }
    public string TestResult { get; set; }
}

Поскольку я очень недолюбливаю XML, в данный момент я получаю такие данные (ztr XmlDocument):

public List<TestGroup> GetTestGroups()
        {
            List<TestGroup> TestNode = new List<TestGroup>();

            string[] type_t = new string[GetTestsNumber()];
            string[] name_t = new string[GetTestsNumber()];
            string[] result_t = new string[GetTestsNumber()];

            //name
            string xpath = "/Document/Tests/Test";

            int i = 0;

            foreach (XmlElement Name in ztr.SelectNodes(xpath))
            {
                name_t[i] = Name.SelectSingleNode("Name").InnerText;
                i++;
            }
            ///////////

            //result
            xpath = "/Document/Tests/Test";

            i = 0;

            foreach (XmlElement Result in ztr.SelectNodes(xpath))
            {
                result_t[i] = Result.SelectSingleNode("Result").InnerText;
                i++;
            }
            /////////////////
            xpath = "/Document/Tests/Test";

            i = 0;

            foreach (XmlElement Type in ztr.SelectNodes(xpath))
            {
                type_t[i] = Type .SelectSingleNode("Type").InnerText;
                i++;
            }

            int count = type_t.GetLength(0);

            for (i = 0; i < count; i++)
            {
                LUTestGroup node = new LUTestGroup();
                node.TestName = name_t[i];
                node.TestType = type_t[i];
                node.TestResult = result_t[i];

                TestNode.Add(node);
            }

            return TestNode;
        }

Очевидно, этот путь довольно опасен. Он повторяет отдельные моменты времени xml и каждый раз добавляет одно свойство в класс. Также, если вы заметили в примере XML-файл. последний Test не имеет узла Result, поэтому код, который я написал, иногда дает сбой при подаче в разные XML-файлы.

Не могли бы вы мне помочь, пожалуйста, напишите метод безопасного получения списка, который будет заполнен всеми тестами, доступными в файле XML, и если у любого из них нет узла, метод не завершится сбоем? и, должно быть, важно, делает ли это работу в ONE GO!

Спасибо

Ответы [ 2 ]

4 голосов
/ 14 октября 2011

(как отмечено в комментариях.)

Версия LINQ to XML действительно проста:

// Could use doc.Root.Element("Tests").Elements("Test") to be explicit
return doc.Descendants("Test")
          .Select(x => new LUTestGroup {
                      TestName = (string) x.Element("Name"),
                      TestType = (string) x.Element("Type"),
                      TestResult = (string) x.Element("Result")
                  })
          .ToList();

Обратите внимание, что приведение от XElement к string вернет ноль, если вы дадите ему нулевую ссылку XElement, поэтому в вашем случае "теста на утечку" вы получите LUTestGroup с свойство null TestResult.

3 голосов
/ 14 октября 2011

Мне кажется, что вы делаете это нелегко. Позвольте системе разобрать xml для вас! Вы можете аннотировать классы, чтобы сказать, как выглядит xml:

[XmlRoot("Document")]
public class TestWrapper {
    private readonly List<TestGroup> tests = new List<TestGroup>();
    [XmlArray("Tests"), XmlArrayItem("Test")]
    public List<TestGroup> Tests { get { return tests; } }
}

public class TestGroup {
    [XmlElement("Name")] public string TestName { get; set; }
    [XmlElement("Type")] public string TestType { get; set; }
    [XmlElement("Result")] public string TestResult { get; set; }
}

тогда:

TestWrapper doc;
using(var reader = XmlReader.Create(source))
{
    var serializer = new XmlSerializer(typeof (TestWrapper));
    doc = (TestWrapper) serializer.Deserialize(reader);
}
// et voila; loaded! prove it:
foreach(var item in doc.Tests)
{
    Console.WriteLine("{0}: {1}, {2}",
        item.TestName, item.TestType, item.TestResult);
}

Вы также можете использовать XmlSerializer - создать xml с тем же макетом, хотя (довольно избыточно, IMO) /Document/Tests/@Count - это боль - я мог бы показать вам, как это исправить, если вы действительно нужно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...