#c# #xml #xpath
#c# #xml #xpath
Вопрос:
У меня есть такой 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 is 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-файле, и если у какого-либо из них нет узла, метод не сработает? и, что очень важно, выполняет работу за ОДИН РАЗ!
Спасибо
Комментарии:
1. Обязательно ли использовать XmlDocument? LINQ to XML сделал бы это намного приятнее, если вы можете использовать .NET 3.5.
2. все мои другие методы также основаны на XmlDocument, на данный момент я не думаю об использовании LINQ. Но было бы неплохо, если бы вы привели пример для этого XML-файла в LINQ, тогда я постараюсь создать свои другие методы на основе этого.
Ответ №1:
(Как указано в комментариях.)
Версия 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();
Обратите внимание, что приведение from XElement
to string
вернет null, если вы дадите ему нулевую XElement
ссылку, поэтому в вашем случае «тест на утечку» вы получите свойство with LUTestGroup
с нулевым TestResult
значением.
Комментарии:
1. Можете ли вы рассказать plesae, как следует объявлять «doc»? У меня это как «doc = new XPathDocument (filePath);» Я думаю, я должен использовать XDocument, как его определить?
2. @Sean87: использование
XDocument doc = XDocument.Load(filePath);
Ответ №2:
Мне кажется, что вы делаете это трудным путем. Пусть система анализирует 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
— это боль — я мог бы показать вам, как это исправить, если вам действительно нужно.
Комментарии:
1. Спасибо за советы! Я думаю, как сказал Джон, Linq будет менее головным способом.