使用 C# 从 XML 中检索文本

Posted

技术标签:

【中文标题】使用 C# 从 XML 中检索文本【英文标题】:Retrieving text from XML with C# 【发布时间】:2020-04-07 15:50:52 【问题描述】:

我有一个包含以下内容的文本文件:

<Person>
    <Prenom>Jack</Prenom>
    <Nom>Jhon</Nom>
    <Adresse>4 rue de la Mélandine</Adresse>
    <Tél></Tél>
    <Email>email@gmail.com</Email>
    <PhotoPath>c:\Program Files\Zonedetec\Gestionnaire de tâche v2\Img\5295f1ea-372a-4f2f-8f32-c52e8a48cc0839105.png</PhotoPath>
    <Age>19</Age>
    <Id>4640434</Id>
</Person>
<Person>
    <Prenom>Jean</Prenom>
    <Nom>Delamar</Nom>
    <Adresse>13 rue de la Mélandine</Adresse>
    <Tél></Tél>
    <Email>email@gmail.com</Email>
    <PhotoPath>c:\Program Files\Zonedetec\Gestionnaire de tâche v2\Img\5295f1ea-372a-4f2f-8f32-c52e8a48cc0839105.png</PhotoPath>
    <Age>19</Age>
    <Id>4640434</Id>
</Person>

我想检索标签之间的所有值 例如,在一个列表中,我想检索和

之间的值(这里是 2)

我该怎么做?

我试过了:

internal static void LoadPerson()
    
        string data = File.ReadAllText(Main.PersonnePath);

        Regex regex = new Regex("<Person>(.*)</Person>");
        var v = regex.Match(data);
        string s = v.Groups[1].ToString();

        MessageBox.Show(s);
    

除了 s 什么都不包含

你能帮帮我吗? 谢谢你。

【问题讨论】:

Person 标签之间有两个以上的值。您的文件是纯 XML 文件,您可以使用 XmlSerializer 并将您的 xml 反序列化为对象以获取任何字符串而不是 你为什么要从我身边夺走我的你好?没有资格打招呼? 正如@PavelAnikhouski 所说,您需要使用XmlSerializer -> docs.microsoft.com/en-us/dotnet/api/… @PavelAnikhouski 的答案是正确的,只是它在这里不起作用,因为您的 XML 不正确。它有两个 Person 标签,但它们必须是一个根标签。所以 XMLSerializer 会失败。如果它只是示例并且原始文件具有像&lt;persons&gt; 这样的包装标签,那么 XMLSerializer 将起作用。 @SumitGupta 我同意你的看法。也许他不知道 XML 是什么。因此,我在回答中解释了两种方式。我也赞成 Pavel 的回答,因为它提供了非常好的使用 C# 处理 XML 的信息。 【参考方案1】:

如果您只需要将此值作为纯文本。您可以使用正则表达式或 XMLSerializer 或 (Linq to XML)。

在选择一种或另一种方法之前,您需要分析的是:

1) 我需要做什么?

1.a) 如果您只需要每个标签内的纯文本。而且你不会做任何验证/计算/重新解析器。您可以轻松地使用这两种方法。

1.a.1) 使用正则表达式:

    public List<string> GetValueByRegex(string input)
    
        string pattern = @"<Person>([\s\S]*?)</Person>";

        var matches = Regex.Matches(input, pattern);

        if (matches.All(m => !m.Success))
            return null;

        var result = new List<string>();
        foreach (Match match in matches)
        
            result.Add(match.Groups[1].Value);
        
        return result;
    

1.a.2) 使用 XDocument 解析 Xml 字符串

重要提示:XDocument 要求您的 XML 有一个根标签才能工作。因为您的 XML 有两个根标签。我用字符串插值强制它$"&lt;root&gt;input&lt;/root&gt;"

    public List<string> GetValueByXmlParse(string input)
    
        var result = new List<string>();
        var ensureThereAreOnlyOneRootTag = $"<root>input</root>";

        XDocument xmlDocument = XDocument.Parse(ensureThereAreOnlyOneRootTag);
        foreach(var personXml in xmlDocument.Root.Elements("Person"))
        
            result.Add(String.Concat(personXml.Nodes()));
        
        return result;
    

1.b) 如果您将对从 XML 中提取的数据做任何事情,最好将其解析为对象。

您可以通过复制 XML 值并单击“编辑”>“选择性粘贴”>“将 XML 粘贴为类”来使 Visual Studio 生成一个。

@PavelAnikhouski 已经分享了一个很好的例子。

2) 我真的需要一个好的表现吗?

回答我使用 Benchmark nuget 包来比较所有选项。结果如下:

|                Method |    Gen 0 | Allocated |
|---------------------- |---------:|----------:|
|       GetValueByRegex |   1.2207 |    2688 B |
|    GetValueByXmlParse | 115.6006 |  243536 B |

第 0 代:GC 第 0 代每 1000 次操作收集一次

Allocated :为每个操作分配的内存(仅限托管,含,1KB = 1024B)

所以,答案是:取决于你需要对结果做什么。我希望我能帮助你做出决定。

最好的问候

【讨论】:

您好,非常感谢您这么详细的回答!你真的让我明白了,一切正常! 欢迎。很高兴我能提供帮助。【参考方案2】:

由于您的文件是 XML 格式,您可以使用 XmlSerializer 来读取它,这比手动解析它不那么痛苦

首先创建一个Person 类(或在Visual Studio 中使用编辑-> 选择性粘贴-> 将XML 粘贴为类 生成)

[Serializable]
public class Person

    private string _prenomField;
    private string _nomField;
    private string _adresseField;
    private object _télField;
    private string _emailField;
    private string _photoPathField;
    private byte _ageField;
    private uint _idField;

    public string Prenom
    
        get => _prenomField;
        set => _prenomField = value;
    

    public string Nom
    
        get => _nomField;
        set => _nomField = value;
    

    public string Adresse
    
        get => _adresseField;
        set => _adresseField = value;
    

    public object Tél
    
        get => _télField;
        set => _télField = value;
    

    public string Email
    
        get => _emailField;
        set => _emailField = value;
    

    public string PhotoPath
    
        get => _photoPathField;
        set => _photoPathField = value;
    

    public byte Age
    
        get => _ageField;
        set => _ageField = value;
    

    public uint Id
    
        get => _idField;
        set => _idField = value;
    

比稍微更新文件结构(你必须有一个根标签)

<?xml version="1.0" encoding="utf-8" ?>
<people>
  <Person>
    <Prenom>Jack</Prenom>
    <Nom>Jhon</Nom>
    <Adresse>4 rue de la Mélandine</Adresse>
    <Tél></Tél>
    <Email>email@gmail.com</Email>
    <PhotoPath>c:\Program Files\Zonedetec\Gestionnaire de tâche v2\Img\5295f1ea-372a-4f2f-8f32-c52e8a48cc0839105.png</PhotoPath>
    <Age>19</Age>
    <Id>4640434</Id>
  </Person>
  <Person>
    <Prenom>Jean</Prenom>
    <Nom>Delamar</Nom>
    <Adresse>13 rue de la Mélandine</Adresse>
    <Tél></Tél>
    <Email>email@gmail.com</Email>
    <PhotoPath>c:\Program Files\Zonedetec\Gestionnaire de tâche v2\Img\5295f1ea-372a-4f2f-8f32-c52e8a48cc0839105.png</PhotoPath>
    <Age>19</Age>
    <Id>4640434</Id>
  </Person>
</people>

最后解析它

var mySerializer = new XmlSerializer(typeof(Person[]), new XmlRootAttribute("people"));
Person[] people;
using (var fileStream = new FileStream(Main.PersonnePath, FileMode.Open))

    people = (Person[])mySerializer.Deserialize(fileStream);

不要忘记添加 using System.Xml.Serialization; 命名空间。反序列化后people 数组将包含您需要的所有值,您可以将它们格式化为任何字符串/任何您想要的。这里最好的选择是覆盖Person 类的ToString() 方法以获得所需的对象字符串表示

【讨论】:

以上是关于使用 C# 从 XML 中检索文本的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 c# 从标签之间的 XML 检索数据?

C#如何检索存储在BLOB中的XML,然后更新它并存储

c# sqlite - 从数据库中检索 BLOB 文本

从mysql中检索图像并设置为pictureBox C#

使用 SendMessage 从闪烁控件中检索文本

如何在 C# 中使用正则表达式检索选定的文本?