【问题标题】:Handling C# XML Deserialization with Namespaces使用命名空间处理 C# XML 反序列化
【发布时间】:2017-02-02 14:15:56
【问题描述】:

我一直在努力反序列化以下 XML 文档:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:settings xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main" mc:Ignorable="w14 w15">
    <w:zoom w:percent="100"></w:zoom>
    <w:proofState w:spelling="clean" w:grammar="clean"></w:proofState>
    <w:defaultTabStop w:val="720"></w:defaultTabStop>
    <w:characterSpacingControl w:val="doNotCompress"></w:characterSpacingControl>
    <w:compat>
        <w:compatSetting w:name="compatibilityMode" w:uri="http://schemas.microsoft.com/office/word" w:val="15"></w:compatSetting>
        <w:compatSetting w:name="overrideTableStyleFontSizeAndJustification" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting>
        <w:compatSetting w:name="enableOpenTypeFeatures" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting>
        <w:compatSetting w:name="doNotFlipMirrorIndents" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting>
        <w:compatSetting w:name="differentiateMultirowTableHeaders" w:uri="http://schemas.microsoft.com/office/word" w:val="1"></w:compatSetting>
    </w:compat>
    <w:rsids>
        <w:rsidRoot w:val="00B31FC7"></w:rsidRoot>
        <w:rsid w:val="00251096"></w:rsid>
        <w:rsid w:val="00481AA7"></w:rsid>
        <w:rsid w:val="005C6856"></w:rsid>
        <w:rsid w:val="00661DE2"></w:rsid>
        <w:rsid w:val="00984D97"></w:rsid>
        <w:rsid w:val="00A06ADC"></w:rsid>
        <w:rsid w:val="00B31FC7"></w:rsid>
    </w:rsids>
    <m:mathPr>
        <m:mathFont m:val="Cambria Math"></m:mathFont>
        <m:brkBin m:val="before"></m:brkBin>
        <m:brkBinSub m:val="--"></m:brkBinSub>
        <m:smallFrac m:val="0"></m:smallFrac>
        <m:dispDef></m:dispDef>
        <m:lMargin m:val="0"></m:lMargin>
        <m:rMargin m:val="0"></m:rMargin>
        <m:defJc m:val="centerGroup"></m:defJc>
        <m:wrapIndent m:val="1440"></m:wrapIndent>
        <m:intLim m:val="subSup"></m:intLim>
        <m:naryLim m:val="undOvr"></m:naryLim>
    </m:mathPr>
    <w:themeFontLang w:val="en-US"></w:themeFontLang>
    <w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink"></w:clrSchemeMapping>
    <w:shapeDefaults>
        <o:shapedefaults v:ext="edit" spidmax="1026"></o:shapedefaults>
        <o:shapelayout v:ext="edit">
            <o:idmap v:ext="edit" data="1"></o:idmap>
        </o:shapelayout>
    </w:shapeDefaults>
    <w:decimalSymbol w:val="."></w:decimalSymbol>
    <w:listSeparator w:val=","></w:listSeparator>
    <w15:chartTrackingRefBased></w15:chartTrackingRefBased>
    <w15:docId w15:val="{23720E07-DD19-46BC-8098-ED32713AB32B}"></w15:docId>
</w:settings>

我只对 rsids 元素中包含的内容感兴趣。所以我想我可以创建如下所示的类:

 [XmlRoot(ElementName ="settings", Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")]
    public class rsids
    {
        [XmlElement(ElementName ="rsids",Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")]
        public List<rsid> Rsids { get; set; }
    }

    public class rsid
    {
        [XmlAttribute(Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")]
        public static string val { get; set; }
    }

我正在尝试像这样反序列化:

XDocument xdoc = XDocument.Load(file);
        using (TextReader reader = new StringReader(xdoc.ToString()))
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(rsids));
                StreamReader sr = new StreamReader(file);
                rsids SettingsXml = (rsids)xmlSerializer.Deserialize(sr);

                foreach (var rsid in SettingsXml.Rsids)
                {
                    Console.WriteLine(rsid.val.Count());
                }

                Console.ReadLine();

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                Console.ReadLine();
            }
        }

但是,我收到以下错误:“值不能为空”。这是我第一次尝试使用命名空间反序列化 XML 文档。我浏览了社区,发现很多有类似问题的人的文章,但是,在尝试了其中一些解决方案之后,我和刚开始时一样困惑,只是在兜圈子。我想明白这一点。其中一些已发布的解决方案似乎表明我只需向我的装饰器(命名空间 =“”)添加一个空白命名空间属性,而其他一些则显示被引用的实际命名空间 uri,但仅适用于根元素,在后续元素 \ 属性中留下空白.我更多的是寻找关于“为什么”\“何时”使用一种方法而不是另一种方法的教育,以及如何在下面给出 XML 的情况下完成此操作的示例。感谢您提供的任何帮助。

干杯

【问题讨论】:

    标签: c# xml serialization namespaces


    【解决方案1】:

    离你不远了。

    1. 您的XmlElement 属性意味着多个rsids 元素。您想要的是包含多个 rsid 元素的单个 rsids 元素。最简单的方法是使用XmlArrayXmlArrayItem 属性。
    2. val 属性不应为 static
    3. 由于看起来像 a bug in XmlSerializer,因此您需要在 XmlAttribute 属性中包含 Form = XmlSchemaForm.Qualified

    您也可以省略大部分 Namespace 属性,因为它们将被继承,并且不必明确指定 ElementName

    将所有这些放在一起:

    [XmlRoot(Namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main")]
    public class settings
    {
        [XmlArray("rsids")]
        [XmlArrayItem("rsid")]
        public List<rsid> Rsids { get; set; }
    }
    
    public class rsid
    {
        [XmlAttribute(Form = XmlSchemaForm.Qualified)]
        public string val { get; set; }
    }
    

    当然,如果这就是你想要的,那么一个简单的 LINQ to XML 查询会容易得多:

    XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
    
    var rsids = doc.Descendants(w + "rsid")
        .Attributes(w + "val")
        .Select(x => x.Value);
    

    请参阅this fiddle 了解两种方法的工作演示。

    【讨论】:

    • 感谢您的解释。我更接近于理解如何正确序列化 XML。您的代码运行良好,.NET Fiddle 非常酷。我不知道这个网站 - 感谢您的帮助。
    【解决方案2】:

    试试这个

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Xml;
    using System.Xml.Linq;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            const string FILENAME = @"c:\temp\test.xml";
            static void Main(string[] args)
            {
                XDocument doc = XDocument.Load(FILENAME);
    
                int[] rsids = doc.Descendants().Where(x => x.Name.LocalName == "rsids").Select(x => new  {
                    rsids = x.Elements().Select(y => int.Parse((string)y.Attribute(x.GetNamespaceOfPrefix("w") + "val"), System.Globalization.NumberStyles.HexNumber))
                }).Select(x => x.rsids).FirstOrDefault().Select(x => x).ToArray();
    
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-28
      • 2012-06-17
      • 1970-01-01
      • 2013-05-02
      • 2015-11-03
      • 2022-01-03
      • 2011-06-25
      相关资源
      最近更新 更多