具有多个不同文本元素的XML元素

3

作为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上返回空字符串时,我该如何将每个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;
        }
    }
}

在上述每个if语句中,NodeType返回为Text,而Name为空字符串。

你的意思是想获取RegisterEntry中的所有子节点,无论它们是否存在? - er-sho
@AllenJones,你在这里使用了while循环,并将所有值收集到单个变量中,因此你的变量仅保存了while循环的最后一次迭代值。因此,你只想要xml中的最后一个RegisterEntry - er-sho
@ershoaib - 是的,我需要获取所有子节点,无论它们是否存在。 我没有包含我的全部代码,因为它是一本冗长的书,但在每次迭代中,我都将变量附加到列表中,以便在进程的后期使用。 - Allen Jones
@YeldarKurmangaliyev - 我会查看XDocument,看看它是否有帮助。 - Allen Jones
2
@AllenJones 在99.9%的情况下,你实际上不需要使用XmlTextReader。只需将此XML文件反序列化为您的对象即可。 - Yeldar Kurmangaliyev
显示剩余6条评论
2个回答

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;
    // ...
}

另一个选择是将元素内容读取为字符串

switch (reader.Name)
{
    case "EntryNumber":
        propEntryNo = reader.ReadElementContentAsString();
        break;
    // ...
}

当然,这些简单的示例假定XML处于预期的格式。您应该在代码中包含适当的检查。
至于其他建议的解决方案:

1
如果使用DOM解析器,我可能会建议使用XDocument而不是XmlDocument,因为API更容易使用。 - Joey
谢谢您。我会尝试这个例子。 - Allen Jones

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();
    }
}

输出:

enter image description here

您还可以对列表执行某些操作,例如:

//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();

谢谢,我也会尝试这些例子。 - Allen Jones
@AllenJones,如果答案对您有帮助,请在答案左侧打勾以使其变为绿色,并通过点击向上箭头投票来赞成答案 :) - er-sho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接