C# 如何反序列化类的特定项子集

C# 如何反序列化类的特定项子集,c#,xml,serialization,C#,Xml,Serialization,我有这个类来反序列化我的类: public class Serializer <T> { public T SerializeAppPath(string xmlpath) { T apppath; using (TextReader txtReader = new StreamReader(xmlpath)) { XmlSerializer xmlSerializer = new XmlSeri

我有这个类来反序列化我的类:

public class Serializer <T> {
       public T SerializeAppPath(string xmlpath) {
           T apppath;
           using (TextReader txtReader = new StreamReader(xmlpath)) {
               XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
               apppath = (T)xmlSerializer.Deserialize(txtReader);
               return apppath;
           }
       }
} 
一些XML示例:

<?xml version="1.0" encoding="utf-8"?>
<KPIPATHS>
<KPIS>
    <KPI>
      <Name>AXD</Name>
      <RequestTemplateFullPath>D:\something</RequestTemplateFullPath>
      <RequestFullPath>D:\something</RequestFullPath>
      <ResultFullPath>D:\something</ResultFullPath>
    </KPI>
    <KPI>
      <Name>DRE</Name>
      <RequestTemplateFullPath>D:\something</RequestTemplateFullPath>
      <RequestFullPath>D:\something</RequestFullPath>
      <ResultFullPath>D:\something</ResultFullPath>
    </KPI>
</KPIS>

AXD
D:\什么
D:\什么
D:\什么
直肠指诊
D:\什么
D:\什么
D:\什么

使用
XmlSerializer
将始终对给定类型上的所有内容进行反序列化/序列化。您正在尝试有条件地查询另一个函数的XML文档。XmlSerialization不应用作XML查询,而应获取给定类型的全部内容并将其完全序列化为XML,或从XML反序列化给定类型的新实例。此外,在给定的序列化链中只能定义一个XmlRoot属性

从MSDN:

有两个属性可以应用于类(并且只有 类):XmlRootAttribute和XmlTypeAttribute。这些属性是 非常相似。XmlRootAttribute只能应用于一个类: 序列化时表示XML文档的开头的类 和结束元素,换句话说,根元素。这个 另一方面,XmlTypeAttribute可以应用于任何类, 包括根类

有关更多信息,请参见此处:

简言之,您希望在序列化过程中使用另一个节点作为XML根,这是不受支持的


在您的情况下,我会在
KpiPath
类中添加一个函数,以便在类型实例中的数据完全反序列化后(因为函数和方法不可序列化)查询该数据,如下所示:

void Main() {
    XmlSerializer ser = new XmlSerializer(typeof(KpiPath));
    KpiPath newPath = new KpiPath();

    newPath.Kpis.Add(new KPI() {Name = "test", RequestTemplateFullPath = @"C:\test", RequestFullPath = @"C:\test"});
    newPath.Kpis.Add(new KPI() {Name = "test", RequestTemplateFullPath = @"C:\newTest", RequestFullPath = @"C:\newTest"});
    newPath.Kpis.Add(new KPI() {Name = "anotherTest", RequestTemplateFullPath = @"C:\funTest", RequestFullPath = @"C:\funTest"});
    StringBuilder sb = new StringBuilder();
    using(StringWriter writer = new StringWriter(sb)) {
        ser.Serialize(writer, newPath);
    } // end using
    Debug.WriteLine(sb.ToString());

    List<KPI> matches = newPath.KPIFromName("test");

    //For debugging, make sure we get two results (matching the two named test above), print a failure message if not.
    Debug.Assert(matches.Count == 2, "Invalid Count");

}

[XmlRoot("KPIPATHS"), Serializable()]
public sealed class KpiPath {

    [XmlArray("KPIS")]
    public List<KPI> Kpis { get; set; }

    public KpiPath() {
        Kpis = new List<KPI>();
    } // end default constructor

    public List<KPI> KPIFromName(string kpiName) {
        if(String.IsNullOrWhiteSpace(kpiName)) {
            throw new ArgumentNullException("kpiName", "No name provided.");
        } // end if
        List<KPI> matches = new List<KPI>();
        if(this.Kpis.Any()) {
            for(int i = 0; i < this.Kpis.Count; i++) {
                if(this.Kpis[i].Name.ToUpperInvariant() == kpiName.ToUpperInvariant()) {
                    matches.Add(this.Kpis[i]);
                } // end if
            } // end for loop
        } // end if

        return matches;
    } // end function GetFromName

} // end class KpiPath

[Serializable()]
public sealed class KPI {

    [XmlElement("Name")]
    public string Name { get; set; }
    [XmlElement("RequestTemplateFullPath")]
    public string RequestTemplateFullPath { get; set; }
    [XmlElement("RequestFullPath")]
    public string RequestFullPath { get; set; }

    public KPI() {
    } // end default constructor

} // end class KPI
void Main(){
XmlSerializer ser=新的XmlSerializer(typeof(KpiPath));
KpiPath newPath=新KpiPath();
添加(新KPI(){Name=“test”,RequestTemplateFullPath=@“C:\test”,RequestFullPath=@“C:\test”});
添加(新KPI(){Name=“test”,RequestTemplateFullPath=@“C:\newTest”,RequestFullPath=@“C:\newTest”});
添加(新的KPI(){Name=“anotherTest”,RequestTemplateFullPath=@“C:\funTest”,RequestFullPath=@“C:\funTest”});
StringBuilder sb=新的StringBuilder();
使用(StringWriter=新StringWriter(sb)){
serial.Serialize(writer,newPath);
}//结束使用
Debug.WriteLine(sb.ToString());
列表匹配项=newPath.KPIFromName(“测试”);
//对于调试,请确保得到两个结果(匹配上面两个命名的测试),如果没有,请打印一条失败消息。
Assert(matches.Count==2,“无效计数”);
}
[XmlRoot(“KPIPATHS”),可序列化()
公共密封类KpiPath{
[XmlArray(“KPI”)]
公共列表KPI{get;set;}
公共KpiPath(){
KPI=新列表();
}//结束默认构造函数
公共列表KPIFromName(字符串kpiName){
if(String.IsNullOrWhiteSpace(kpiName)){
抛出新的ArgumentNullException(“kpiName”,“未提供名称”);
}//如果结束,则结束
列表匹配项=新列表();
if(this.Kpis.Any()){
对于(int i=0;i
这样,您就有了一种简单的方法来检索具有您感兴趣的名称的项,并且不必有任何复杂/难以遵循的反序列化逻辑

如果这不是一个好的解决方案,我建议您使用
XmlReader
/
XmlDocument
组合,根据XPath()语法从文档中读取特定项

以下是解决此问题的一些相关主题:


  • 您可以包含一些示例XML吗?您可以手动解析
    XML
    (错误),也可以反序列化所有内容(整个
    KPIPATHS
    ),然后执行条件筛选。不,我不想使用XML阅读器或类似的东西。序列化方式就是我选择的方式。您好xDaevax,我将您的方法放在KpiPath类中,并尝试从其他类调用它,如下所示:List ff=KpiPath.KPIFromName(kpiname.ToString());但是它不起作用,因为找不到类型或命名空间KPI?@Bob这可能是因为您在
    KpiPath
    类中声明了
    KPI
    类(您不必这样做,并且可能不需要,因为您已将该类声明为public)。尝试将
    KPI
    类移到
    KpiPath
    类之外。我不能,因为这样我的反序列化程序将停止工作then@Bob,KPI类不需要嵌套在KpiPath类中,就可以工作,它可以在代码中的任何位置,只要您在KpiPath中具有KPI属性并且KPI类是公共的。所以您建议拆分这些类,我的意思是将KPI类带到其他文件,然后使用代码?
    <?xml version="1.0" encoding="utf-8"?>
    <KPIPATHS>
    <KPIS>
        <KPI>
          <Name>AXD</Name>
          <RequestTemplateFullPath>D:\something</RequestTemplateFullPath>
          <RequestFullPath>D:\something</RequestFullPath>
          <ResultFullPath>D:\something</ResultFullPath>
        </KPI>
        <KPI>
          <Name>DRE</Name>
          <RequestTemplateFullPath>D:\something</RequestTemplateFullPath>
          <RequestFullPath>D:\something</RequestFullPath>
          <ResultFullPath>D:\something</ResultFullPath>
        </KPI>
    </KPIS>
    
    void Main() {
        XmlSerializer ser = new XmlSerializer(typeof(KpiPath));
        KpiPath newPath = new KpiPath();
    
        newPath.Kpis.Add(new KPI() {Name = "test", RequestTemplateFullPath = @"C:\test", RequestFullPath = @"C:\test"});
        newPath.Kpis.Add(new KPI() {Name = "test", RequestTemplateFullPath = @"C:\newTest", RequestFullPath = @"C:\newTest"});
        newPath.Kpis.Add(new KPI() {Name = "anotherTest", RequestTemplateFullPath = @"C:\funTest", RequestFullPath = @"C:\funTest"});
        StringBuilder sb = new StringBuilder();
        using(StringWriter writer = new StringWriter(sb)) {
            ser.Serialize(writer, newPath);
        } // end using
        Debug.WriteLine(sb.ToString());
    
        List<KPI> matches = newPath.KPIFromName("test");
    
        //For debugging, make sure we get two results (matching the two named test above), print a failure message if not.
        Debug.Assert(matches.Count == 2, "Invalid Count");
    
    }
    
    [XmlRoot("KPIPATHS"), Serializable()]
    public sealed class KpiPath {
    
        [XmlArray("KPIS")]
        public List<KPI> Kpis { get; set; }
    
        public KpiPath() {
            Kpis = new List<KPI>();
        } // end default constructor
    
        public List<KPI> KPIFromName(string kpiName) {
            if(String.IsNullOrWhiteSpace(kpiName)) {
                throw new ArgumentNullException("kpiName", "No name provided.");
            } // end if
            List<KPI> matches = new List<KPI>();
            if(this.Kpis.Any()) {
                for(int i = 0; i < this.Kpis.Count; i++) {
                    if(this.Kpis[i].Name.ToUpperInvariant() == kpiName.ToUpperInvariant()) {
                        matches.Add(this.Kpis[i]);
                    } // end if
                } // end for loop
            } // end if
    
            return matches;
        } // end function GetFromName
    
    } // end class KpiPath
    
    [Serializable()]
    public sealed class KPI {
    
        [XmlElement("Name")]
        public string Name { get; set; }
        [XmlElement("RequestTemplateFullPath")]
        public string RequestTemplateFullPath { get; set; }
        [XmlElement("RequestFullPath")]
        public string RequestFullPath { get; set; }
    
        public KPI() {
        } // end default constructor
    
    } // end class KPI