C# 从xml(格式错误?)c检索数据

C# 从xml(格式错误?)c检索数据,c#,xml,linq,C#,Xml,Linq,我刚开始使用xml和C以及linq 我有这种xml <allegati tot_ele="2"> <record> <dato nome="IdUnivoco">35516</dato> <dato nome="Nome">QUOTAZIONE</dato> <dato nome="RelationID">1268</dato> <dato nome="nomeFile">1268.pdf

我刚开始使用xml和C以及linq

我有这种xml

<allegati tot_ele="2">
<record>
<dato nome="IdUnivoco">35516</dato>
<dato nome="Nome">QUOTAZIONE</dato>
<dato nome="RelationID">1268</dato>
<dato nome="nomeFile">1268.pdf</dato>
</record>
<record>
<dato nome="IdUnivoco">35516</dato>
<dato nome="Nome">CONFERMA D`ORDINE</dato>
<dato nome="RelationID">1267</dato>
<dato nome="nomeFile">1267.pdf</dato>
</record>
</allegati>
创建它的人使用相同的元素名称并使用属性来指定值的名称

是否有一种简单的方法为每个记录创建一个结构,并使用linq创建一个结构列表

目前,我设法创建了4个不同的字符串列表,我只发布了2个,而不是全部4个

List<string> NomeFile1 = (from c in listaAttch.Descendants("dato")
                          where c.Attribute("nome").Value == "nomeFile"
                          select c.Value).ToList();

List<string> Relation = (from c in listaAttch.Descendants("dato")
                          where c.Attribute("nome").Value == "RelationID"
                          select c.Value).ToList();
然后使用for,我将根据需要使用4个字符串

for (int i = 0; i < Relation.Count; i++)
 {
  byte[] file = Adiuto.getAttachContent1(login, 35516, Int32.Parse(Relation [i]));
  System.IO.File.WriteAllBytes("c:\\navision\\" + NomeFile1[i], file);
.
.
.
 }
有没有更快更优雅的方法?不需要重复linq 4次? 创建包含所有4个属性值的结构列表也可以吗

非常感谢


Fabrizio

您可以将查询提取到专用方法,并将不同的值作为参数注入:

private List<string> GetDescendantsValues(SomeType source, string attributeValue)
{
    return source.Descendants("dato")
        .Where(c => c.Attribute("nome").Value == attributeValue)
        .Select(c => c.Value).ToList();
}
用法:

List<string> NomeFile1 = GetDescendantsValues(listaAttch, "nomeFile");
List<string> Relation = GetDescendantsValues(listaAttch, "RelationID");

当然,如果需要,您也可以插入其他字符串,我只为1注入了这些字符串,因为这是您呈现的代码中唯一不同的字符串。

是的,您可以使用XmlNodeReader反序列化非标准xml字符串。在我的一个项目中,我做了同样的事情

转换任意xml字符串的扩展方法-

public static class XmlSerializerExtensions
{
    public static T DeserializeFromNonStandardXmlString<T>(string content)
    {
        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(content);

        var serializer = typeof(T).IsGenericType ? new XmlSerializer(typeof(T), typeof(T).GenericTypeArguments) : new XmlSerializer(typeof(T));
        using (var reader = new XmlNodeReader(xmlDoc))
        {
            return (T)serializer.Deserialize(reader);
        }
    }

    public static object DeserializeFromNonStandardXmlString(Type type, string content)
    {
        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(content);

        var serializer = type.IsGenericType ? new XmlSerializer(type, type.GenericTypeArguments) : new XmlSerializer(type);
        using (var reader = new XmlNodeReader(xmlDoc))
        {
            return serializer.Deserialize(reader);
        }
    }
}
您还可以使用一种方法来减少此代码-

    [XmlRoot(ElementName = "allegati")]
    public class Allegati
    {
        ...

        public List<string> GetItemsWithKey(string key)
        {
            return Record.Select(x => x.Dato.FirstOrDefault(d => d.Nome == key)?.Text).ToList();
        }
    }



    var dt = XmlSerializerExtensions.DeserializeFromNonStandardXmlString<Allegati>(text);
    var a = dt.GetItemsWithKey("nomeFile");
    var b = dt.GetItemsWithKey("RelationID");

请注意,此XML没有任何格式错误甚至异常之处。它不是Linq设计用来轻松处理的XML类型。
var dt = XmlSerializerExtensions.DeserializeFromNonStandardXmlString<Allegati>(text);
var NomeFile1 = dt.Record.Select(x => x.Dato.FirstOrDefault(d => d.Nome == "nomeFile")?.Text).Select(x => x != null).ToList();
var Relation = dt.Record.Select(x => x.Dato.FirstOrDefault(d => d.Nome == "RelationID")?.Text).Select(x => x != null).ToList();
    [XmlRoot(ElementName = "allegati")]
    public class Allegati
    {
        ...

        public List<string> GetItemsWithKey(string key)
        {
            return Record.Select(x => x.Dato.FirstOrDefault(d => d.Nome == key)?.Text).ToList();
        }
    }



    var dt = XmlSerializerExtensions.DeserializeFromNonStandardXmlString<Allegati>(text);
    var a = dt.GetItemsWithKey("nomeFile");
    var b = dt.GetItemsWithKey("RelationID");