具有多个不同 Text 元素的 XML 元素

Posted

技术标签:

【中文标题】具有多个不同 Text 元素的 XML 元素【英文标题】:XML element with multiple different Text elements 【发布时间】:2019-03-29 22:21:07 【问题描述】:

我将以下元素作为 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;
        
    

在上面的每个 if 语句中,NodeType 以 Text 形式返回,而 Name 以空字符串形式返回。

【问题讨论】:

你能给我们看一些代码吗? 表示你想获取RegisterEntry内的所有子节点,不管它们是否存在? 您的 XML 显示 RegisterEntry 有子元素,那么它们怎么可能是文本节点呢?您的 XML 或您的解释不正确。 显示代码! 原始帖子已编辑以包含代码。 XML 文件来自英国的土地注册处。 @AllenJones 在 99.9% 的情况下,您实际上不需要使用 XmlTextReader。只需将此 XML 文件反序列化为您的对象即可。 【参考方案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 转换为对象是另一种选择。但是我觉得处理由意外格式引起的错误比较棘手。

【讨论】:

如果使用 DOM 解析器,我可能会建议使用 XDocument 而不是 XmlDocument,因为该 API 更易于使用。 谢谢。我会试试这个例子。【参考方案2】:

您可以使用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();

【讨论】:

谢谢,我也会试试这些例子。 @AllenJones,如果答案对您有帮助,请标记答案左侧的勾号使其变为绿色,然后通过单击向上箭头进行投票以回答 :)

以上是关于具有多个不同 Text 元素的 XML 元素的主要内容,如果未能解决你的问题,请参考以下文章

多个同名但类型不同的元素

具有不同属性的 xml dtd 或 xml 模式链接元素

使用 SAX 解析器,如何解析具有相同名称标签但元素不同的 xml 文件?

当我们有多个同名但属性不同的元素时,如何使用 Xdocument 从 xml 中删除一个元素

Flutter : 使具有不同图标大小的 IconButtons 和 Row 中的 Text 元素对齐到中心

具有相同元素名称但属性值不同的XML的XSD架构[关闭]