代码之家  ›  专栏  ›  技术社区  ›  Jared Updike

使用xmlseralizer在C中解析稍微不稳定的XML

  •  2
  • Jared Updike  · 技术社区  · 15 年前

    我得到了一些“xml”文件,它们没有一个合适的模式(我认为这就是问题所在),并且生成它们的医疗设备无法更改为生成易于解析的xml。(用如此诱人的小改动(额外包装) 图像 周围的标签 图像 条目)读取这些文件很简单——这不是XML的目的吗?)

    基本上我被困在这里。XML如下所示:

    <Series>
       <Metadata1>foo</Metadata1>
       <Metadata2>bar</Metadata2>
       ...
       <Image>...</Image>
       <Image>...</Image>
       ...
    </Series>
    

    (可以有任意数量的图像,但可能的元数据标记都是已知的)。我的代码如下:

    public class Image { ... }
    
    public class Series : List<Image>
    {
        public Series() { }
        public string Metadata1;
        public string Metadata2;
        ...
    }
    

    当我这样运行时:

                XmlSerializer xs = new XmlSerializer(typeof(Series));
                StreamReader sr = new StreamReader(path);
                Series series = (Series)xs.Deserialize(sr);
                sr.Close();
    

    图像对象列表正确读取到序列对象中,但未读取元数据1/2/etc字段(事实上,在调试器中浏览对象会显示“原始视图”类字段中的所有元数据字段)。

    当我更改代码时:

    public class Series    // // removed this : List<Image>
    {
        public Series() { }
        public string Metadata1;
        public string Metadata2;
        ...
    }
    

    在文件上运行读卡器,我得到一个包含metadata1/2/etc的序列对象,它被完美地填充了,但是没有读取图像数据(显然)。

    我如何用最少痛苦的即席代码来解析metadata1/2/etc和一系列图像?

    我需要写一些习惯吗(痛苦?容易吗?)readxml方法实现Ixmlseralizable?

    我不太关心对象的布局,因为使用这些C类的软件是完全灵活的:

    List<Image> Images;
    因为图像很好,或者元数据被包装在某个对象中,无论什么…
    3 回复  |  直到 15 年前
        1
  •  3
  •   Steve Guidi    15 年前

    你的课不见了 the attributes 允许XML序列化工作的。我相信以下几点就足够了。

    [XmlElement]
    public class Image { ... }
    
    [XmlRoot(ElementName="Series")]
    public class Series
    {
            public Series() { }
    
            [XmlElement]
            public string Metadata1;
    
            [XmlElement]
            public string Metadata2;
    
            [XmlElement(ElementName="Image")]
            public Image[] Images;
    }
    

    我不确定是否可以使用泛型类型来代替图像数组,但是上面引用的链接应该为您提供关于如何为特定情况应用序列化属性的更多信息。

    编辑: 另一种选择是手工制作和XML模式,该模式将验证应用程序生成的文档,然后使用 XSD.exe 生成对象模型。生成的类将演示如何在对象模型之间使用序列化程序。

        2
  •  2
  •   Scott Dorman    15 年前

    为什么要使用XML序列化程序来执行此操作?序列化通常是指能够以某种已知格式(文本或二进制)保存对象的“状态”,以便在以后的某个时间点重新创建该对象。这听起来不像你想在这里做的。这里的问题是XML数据与对象层次结构不匹配。

    您有一个硬件设备,它以某种方式生成要使用的XML数据。对我来说,使用一个简单的xmlDocument或xmlReader类,而不是尝试遍历序列化程序,这是最简单的。

    您可以使用这样的代码:

    public class Image { }
    
    public class Series
    {
       public string Metadata1;
       public string Metadata2;
       public List<Image> Images = new List<Image>();
    
       public void Load(string xml)
       {
          XmlDocument doc = new XmlDocument();
          doc.Load(xml);
    
          XmlNodeList images = doc.SelectNodes("Image");
          foreach (XmlNode image in images)
          {
             Images.Add(new Image(image.InnerText));
          }
    
          Metadata1 = GetMetadataValue(doc, "Metadata1");
          Metadata2 = GetMetadataValue(doc, "Metadata2");
       }
    
       private string GetMetadataValue(XmlDocument document, string nodeName)
       {
          string value = String.Empty;
          XmlNode metadataNode = document.SelectSingleNode(nodeName);
          if (metadataNode != null)
          {
             value = metaDataNode.InnerText;
          }
    
          return value;
       }
    }
    

    *这是未经测试/未经验证的代码,但它应该能够传达这个想法。

        3
  •  1
  •   Thomas Levesque    15 年前

    我认为史蒂夫的回答应该有效。我只想补充一点,使用这种技术,您只能读取有限数量的元数据元素,因为它们没有常量名。您可以做的是将它们读取到一个xmlElements集合中,稍后您可以对其进行分析:

    [XmlRoot(ElementName="Series")]
    public class Series
    {
        public Series() { }
    
        [XmlAnyElement]
        XmlElement[] UnknownElements;
    
        private string[] _metadata;
        [XmlIgnore]
        public string[] Metadata
        {
            get
            {
                if (_metadata == null && UnknownElements != null)
                {
                    _metadata = UnknownElements
                                .Where(e => e.Name.StartsWith("Metadata")
                                .Select(e => e.InnerText)
                                .ToArray();
                }
                return _metadata;
            }
        }
    
        [XmlElement(ElementName="Image")]
        public Image[] Images;
    }