【问题标题】:How to parse a xml-file using C# and Linq by finding a specific attributes value如何使用 C# 和 Linq 通过查找特定属性值来解析 xml 文件
【发布时间】:2016-02-18 23:06:35
【问题描述】:

我想做什么

我有一个文件夹。在那个文件夹中有pdf、图片等。另外还有一个xmlfile。
该 xmlfile 具有其他文件的元数据。
我想从 xml 中提取数据并将其保存在 c# 类中,以便以后使用

我已经做过的事情

我搜索了一种使用 linq 解析文件的方法。但我无法让它以我想要的方式工作。
我希望它像这样工作:
我有一个存储在我的应用程序中的文件列表。然后我想对每个文件进行循环,并从 xml 中获取该文件的数据。

我有什么

xml 文件如下所示:

<?xml version='1.0' encoding='ISO-8859-1' ?>
<FOLDERS Name="XXXXXXX" >
    <FOLDER Date="12/15/2015 15:25:04" ByUser="" Name="some folders name" Type="" MemberOf="">
        <![CDATA[FOLDERID111]]>
        <VISUALFOLDER Date="02/16/2016 14:25:00" ByUser="" Name="some folders name" Type="" StartView="UNKNOWN" ScreenOffset="0"/>
        <TABSHEET Date="02/16/2016 14:25:00" Name="Fields" Type="IdxFields">
            <![CDATA[TABSHEETID521]]>
            <VISUALTABSHEET Date="02/16/2016 14:25:00" Name="Fields" Type="IdxFields"/>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="DocuName">
                <![CDATA[Something thats not the documents name]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="DocuName"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="DocuDate">
                <![CDATA[09.12.2015]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="DocuDate"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Object">
                <![CDATA[OBJECT1]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Object"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Tag">
                <![CDATA[LETTER]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Tag"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="User">
                <![CDATA[USER1]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="User"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Note">
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Note"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Barcode">
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Barcode"/>
            </INDEXFIELD>
        </TABSHEET>
        <TABSHEET Date="02/16/2016 14:25:00" Name="Documents" Type="Documents" Data="" SeqNo="0" Title="" Password="">
            <![CDATA[TABSHEETID522]]>
            <VISUALTABSHEET Date="02/16/2016 14:25:00" Name="Documents" Type="Documents"/>
            <DOCUMENT Date="02/16/2016 14:25:00" Name="Document" Type="" Data="" FileName="C:\ProgramData\Import\file1.pdf" FileOffset="5712054" FileSize="128509" BinaryType="PDF">
                <VISUALDOCUMENT Date="02/16/2016 14:25:00" Name="Document" Type="" Height="148" Width="105"/>
            </DOCUMENT>
            <DOCUMENT Date="02/16/2016 14:25:00" Name="Document" Type="" Data="" FileName="C:\ProgramData\Import\file2.pdf" FileOffset="5840563" FileSize="129847" BinaryType="PDF">
                <VISUALDOCUMENT Date="02/16/2016 14:25:00" Name="Document" Type="" Height="148" Width="105"/>
            </DOCUMENT>
        </TABSHEET>
    </FOLDER>

<FOLDER Date="12/30/2015 15:25:04" ByUser="" Name="some other folders name" Type="" MemberOf="">
        <![CDATA[FOLDERID111]]>
        <VISUALFOLDER Date="02/16/2016 14:25:00" ByUser="" Name="some other folders name" Type="" StartView="UNKNOWN" ScreenOffset="0"/>
        <TABSHEET Date="02/16/2016 14:25:00" Name="Fields" Type="IdxFields">
            <![CDATA[TABSHEETID521]]>
            <VISUALTABSHEET Date="02/16/2016 14:25:00" Name="Fields" Type="IdxFields"/>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="DocuName">
                <![CDATA[Something thats not the documents name]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="DocuName"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="DocuDate">
                <![CDATA[09.12.2015]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="DocuDate"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Object">
                <![CDATA[OBJECT1]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Object"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Tag">
                <![CDATA[LETTER]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Tag"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="User">
                <![CDATA[USER1]]>
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="User"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Note">
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Note"/>
            </INDEXFIELD>
            <INDEXFIELD Date="02/16/2016 14:25:00" Name="Barcode">
                <VISUALINDEXFIELD Date="02/16/2016 14:25:00" Name="Barcode"/>
            </INDEXFIELD>
        </TABSHEET>
        <TABSHEET Date="02/16/2016 14:25:00" Name="Documents" Type="Documents" Data="" SeqNo="0" Title="" Password="">
            <![CDATA[TABSHEETID522]]>
            <VISUALTABSHEET Date="02/16/2016 14:25:00" Name="Documents" Type="Documents"/>
            <DOCUMENT Date="02/16/2016 14:25:00" Name="Document" Type="" Data="" FileName="C:\ProgramData\Import\file3.pdf" FileOffset="5712054" FileSize="128509" BinaryType="PDF">
                <VISUALDOCUMENT Date="02/16/2016 14:25:00" Name="Document" Type="" Height="148" Width="105"/>
            </DOCUMENT>
        </TABSHEET>
    </FOLDER>
</FOLDERS>

xml 是由另一个应用程序生成的。
每个“文件夹”有两个“标签页”。一个包括数据(可通过“名称”属性识别),另一个包括文件名。
数据包含在 CDATA 块中。有些字段有数据,有些没有。并非每个文档都有“条形码”。

我的问题

Linq 查询看起来像我想做的那样吗?

更新 1

好的,我已将查询修复为几乎可以满足我的要求

            var test1 = xdoc
                .Element("FOLDERS")
                .Elements("FOLDER")
                .Where(xml => xml
                                .Elements("TABSHEET")
                                .Elements("DOCUMENT")
                                .Select(x => x.Attribute("FileName").Value)
                                .ToList()
                                .Contains(file.FilePath)
                )
                .Select(xml => xml
                                .Elements("TABSHEET")
                                .Elements("INDEXFIELD")
                                .Where(x => 
                                    x.Attribute("Name").Value == "DocuName" ||
                                    x.Attribute("Name").Value == "Note" ||
                                    x.Attribute("Name").Value == "User")
                                .Select(x => (string)x.Value)
                );

现在唯一的问题是如何区分结果。
我的意思是:查询将返回一个 IEnumerable>,其中包含 3 个值乘以文件数量。 但是因为它是一个 IEnumerable,所以我无法判断字符串是“DocuName”还是“Note”还是“User”。

有没有办法从这个查询中得到一个带有正确键的字典?

【问题讨论】:

  • 向我们展示你的 linq 查询不起作用
  • “但我无法让它按照我想要的方式工作......我想对每个文件进行循环并从 xml 中获取该文件的数据” - 太模糊也太不可能了
  • 如果不是必须使用 linq,您可以使用 xsd.exe 生成代表您的 xml 的类结构。然后反序列化到这个类并访问数据会相当容易。
  • 对了,有一个关于xsd.exe的答案stackoverflow.com/questions/4203540/…

标签: c# xml linq


【解决方案1】:

有很多方法可以解决这个问题,因为你提到你想要等效的C# 实体我更喜欢这种方法。

为您的 xml 生成 C# 实体(有很多工具)

[XmlRoot(ElementName="VISUALFOLDER")]
public class VISUALFOLDER {
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="ByUser")]
    public string ByUser { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName="Type")]
    public string Type { get; set; }
    [XmlAttribute(AttributeName="StartView")]
    public string StartView { get; set; }
    [XmlAttribute(AttributeName="ScreenOffset")]
    public string ScreenOffset { get; set; }
}

[XmlRoot(ElementName="VISUALTABSHEET")]
public class VISUALTABSHEET {
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName="Type")]
    public string Type { get; set; }
}

[XmlRoot(ElementName="VISUALINDEXFIELD")]
public class VISUALINDEXFIELD {
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
}

[XmlRoot(ElementName="INDEXFIELD")]
public class INDEXFIELD {
    [XmlElement(ElementName="VISUALINDEXFIELD")]
    public VISUALINDEXFIELD VISUALINDEXFIELD { get; set; }
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
}

[XmlRoot(ElementName="TABSHEET")]
public class TABSHEET {
    [XmlElement(ElementName="VISUALTABSHEET")]
    public VISUALTABSHEET VISUALTABSHEET { get; set; }
    [XmlElement(ElementName="INDEXFIELD")]
    public List<INDEXFIELD> INDEXFIELD { get; set; }
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName="Type")]
    public string Type { get; set; }
    [XmlElement(ElementName="DOCUMENT")]
    public List<DOCUMENT> DOCUMENT { get; set; }
    [XmlAttribute(AttributeName="Data")]
    public string Data { get; set; }
    [XmlAttribute(AttributeName="SeqNo")]
    public string SeqNo { get; set; }
    [XmlAttribute(AttributeName="Title")]
    public string Title { get; set; }
    [XmlAttribute(AttributeName="Password")]
    public string Password { get; set; }
}

[XmlRoot(ElementName="VISUALDOCUMENT")]
public class VISUALDOCUMENT {
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName="Type")]
    public string Type { get; set; }
    [XmlAttribute(AttributeName="Height")]
    public string Height { get; set; }
    [XmlAttribute(AttributeName="Width")]
    public string Width { get; set; }
}

[XmlRoot(ElementName="DOCUMENT")]
public class DOCUMENT {
    [XmlElement(ElementName="VISUALDOCUMENT")]
    public VISUALDOCUMENT VISUALDOCUMENT { get; set; }
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName="Type")]
    public string Type { get; set; }
    [XmlAttribute(AttributeName="Data")]
    public string Data { get; set; }
    [XmlAttribute(AttributeName="FileName")]
    public string FileName { get; set; }
    [XmlAttribute(AttributeName="FileOffset")]
    public string FileOffset { get; set; }
    [XmlAttribute(AttributeName="FileSize")]
    public string FileSize { get; set; }
    [XmlAttribute(AttributeName="BinaryType")]
    public string BinaryType { get; set; }
}

[XmlRoot(ElementName="FOLDER")]
public class FOLDER {
    [XmlElement(ElementName="VISUALFOLDER")]
    public VISUALFOLDER VISUALFOLDER { get; set; }
    [XmlElement(ElementName="TABSHEET")]
    public List<TABSHEET> TABSHEET { get; set; }
    [XmlAttribute(AttributeName="Date")]
    public string Date { get; set; }
    [XmlAttribute(AttributeName="ByUser")]
    public string ByUser { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
    [XmlAttribute(AttributeName="Type")]
    public string Type { get; set; }
    [XmlAttribute(AttributeName="MemberOf")]
    public string MemberOf { get; set; }
}

[XmlRoot(ElementName="FOLDERS")]
public class FOLDERS {
    [XmlElement(ElementName="FOLDER")]
    public List<FOLDER> FOLDER { get; set; }
    [XmlAttribute(AttributeName="Name")]
    public string Name { get; set; }
}

现在我们可以使用下面的 sn-p 反序列化它。

StreamReader reader = new StreamReader(filepath);
var folders = (FOLDERS)serializer.Deserialize(reader); 

工作Demo

【讨论】:

    【解决方案2】:

    我想出了以下解决方案:

    file 是我保存文件所有数据的类。

    var elements = xdoc.Element("FOLDERS");
                if (elements == null)
                {
                    throw new KeyNotFoundException();
                }
    
                var data = elements
                    .Elements("FOLDER")
                    .Where(xml => xml
                                    .Elements("TABSHEET")
                                    .Elements("DOCUMENT")
                                    .Select(x => x.Attribute("FileName").Value)
                                    .ToList()
                                    .Contains(file.FileName)
                    )
                    .Select(xml => xml
                                    .Elements("TABSHEET")
                                    .Elements("INDEXFIELD")
                                    .Where(x =>
                                        x.Attribute("Name").Value == "Date" ||
                                        x.Attribute("Name").Value == "Note" 
                                        )
                                    .Select(x => new string[] { (string)x.Attribute("Name"), (string)x.Value }))
                    .ToList();
    
                if (data.Count != 1)
                {
                    file.Upload = false;
                    continue;
                }
    
                var dataDictionary = data[0].ToDictionary(item => item[0],
                    item => item[1]);
    
                file.Date = !dataDictionary.ContainsKey("Date") || string.IsNullOrWhiteSpace(dataDictionary["Date"]) ? new DateTime() : DateTime.Parse(dataDictionary["Date"]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-22
      相关资源
      最近更新 更多