我将以下元素作为XML文档的一部分:
<RegisterEntry>
<EntryNumber>3</EntryNumber>
<EntryDate>2009-01-30</EntryDate>
<EntryType>Registered Charges</EntryType>
<EntryText>REGISTERED CHARGE dated 30 December 2008.</EntryText>
</RegisterEntry>
<RegisterEntry>
<EntryNumber>4</EntryNumber>
<EntryType>Registered Charges</EntryType>
<EntryText>REGISTERED CHARGE dated 30 December 2008.</EntryText>
</RegisterEntry>
我正在使用XmlReader遍历文档。 RegisterEntry是XMLNodeType.Element,并且此元素中包含的四个是XmlNodeType.Text。当XmlReader在NodeType.Text上为Node.Name返回空字符串时,如何将每个Text值分配给不同的变量。同样,重复的元素并不总是具有相同数量的文本元素。下面的代码:
XmlTextReader reader = new XmlTextReader(fName);
if(reader.NodeType == XmlNodeType.Element && reader.Name =="RegisterEntry")
{
propEntryNo = "";
propEntryDate = "";
propEntryType = "";
propEntryText = "";
while(reader.Read())
{
if(reader.NodeType == XmlNodeType.Text && reader.Name == "EntryNumber" && reader.HasValue)
{
propEntryNo = reader.Value;
}
if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryDate" && reader.HasValue)
{
propEntryDate = reader.Value;
}
if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryType" && reader.HasValue)
{
propEntryType = reader.Value;
}
if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryText" && reader.HasValue)
{
propEntryText += reader.Value + ",";
}
if(reader.NodeType == XmlNodeType.EndElement && reader.Name == "RegisterEntry")
{
add variable values to list
break;
}
}
}
在NodeType上方的每个if语句中,返回的都是Text,而Name的返回为空字符串。
答案 0 :(得分:1)
XML元素和其中的文本是不同节点!
您必须首先阅读XML元素的内容。 简单示例:
switch (reader.Name)
{
// found a node with name = "EntryNumber" (type = Element)
case "EntryNumber":
// make sure it's not the closing tag
if (reader.IsStartElement())
{
// read the text inside the element, which is a seperate node (type = Text)
reader.Read();
// get the value of the text node
propEntryNo = reader.Value;
}
break;
// ...
}
另一个选项是ReadElementContentAsString
switch (reader.Name)
{
case "EntryNumber":
propEntryNo = reader.ReadElementContentAsString();
break;
// ...
}
当然,这些简单的示例假定XML为预期格式。您应该在代码中包含适当的检查。
关于其他建议的解决方案:
您可以XmlDocument或XDocument代替。处理起来比较容易,但是使用memory overhead is bigger(see also)。
Deserializing将XML转换为对象是另一种选择。但是我觉得处理意外格式引起的错误比较棘手。
答案 1 :(得分:0)
您可以使用XDocument
列出您的RegisterEntry
子节点,例如
class Program
{
static void Main(string[] args)
{
XDocument doc = XDocument.Load(@"C:\Users\xxx\source\repos\ConsoleApp4\ConsoleApp4\Files\XMLFile14.xml");
var registerEntries = doc.Descendants("RegisterEntry");
var result = (from e in registerEntries
select new
{
EntryNumber = e.Element("EntryNumber") != null ? Convert.ToInt32(e.Element("EntryNumber").Value) : 0,
EntryDate = e.Element("EntryDate") != null ? Convert.ToDateTime(e.Element("EntryDate").Value) : (DateTime?)null,
EntryType = e.Element("EntryType") != null ? e.Element("EntryType").Value : "",
EntryText = e.Element("EntryText") != null ? e.Element("EntryText").Value : "",
}).ToList();
foreach (var entry in result)
{
Console.WriteLine($"EntryNumber: {entry.EntryNumber}");
Console.WriteLine($"EntryDate: {entry.EntryDate}");
Console.WriteLine($"EntryType: {entry.EntryType}");
Console.WriteLine($"EntryText: {entry.EntryText}");
Console.WriteLine();
}
Console.ReadLine();
}
}
输出:
您还可以在列表上进行某些操作,例如。
//If you want to get all `EntryText` in xml to be comma separated then you can do like
string propEntryText = string.Join(", ", result.Select(x => x.EntryText));
//Get first register entry from xml
var getFirstRegisterEntry = result.FirstOrDefault();
//Get last register entry from xml
var getLastRegisterEntry = result.LastOrDefault();
//Get register entry from xml with specific condition
var getSpecificRegisterEntry = result.Where(x => x.EntryNumber == 3).SingleOrDefault();