【问题标题】:Retrieve data from xml (malformed?) c#从 xml 中检索数据(格式错误?) c#
【发布时间】:2017-11-23 16:15:00
【问题描述】:

我开始使用 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 i 将使用 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 个属性值的结构列表

在此先感谢

法布里齐奥

【问题讨论】:

  • 请注意,此 XML 没有任何格式错误(甚至不寻常)。它只是不是 Linq 旨在(轻松地)处理的那种 XML。

标签: c# xml linq


【解决方案1】:

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

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 完成了该操作,因为这是您提供的代码中唯一不同的字符串。

【讨论】:

    【解决方案2】:

    是的,您可以使用 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 = "dato")]
        public class Dato
        {
            [XmlAttribute(AttributeName = "nome")]
            public string Nome { get; set; }
            [XmlText]
            public string Text { get; set; }
        }
    
        [XmlRoot(ElementName = "record")]
        public class Record
        {
            [XmlElement(ElementName = "dato")]
            public List<Dato> Dato { get; set; }
        }
    
        [XmlRoot(ElementName = "allegati")]
        public class Allegati
        {
            [XmlElement(ElementName = "record")]
            public List<Record> Record { get; set; }
    
            [XmlAttribute(AttributeName = "tot_ele")]
            public string Tot_ele { get; set; }
        } 
    

    那你就可以这样序列化了——

    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");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-14
      • 2018-12-10
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-01
      相关资源
      最近更新 更多