XmlReader 创建空字符串 C#

Posted

技术标签:

【中文标题】XmlReader 创建空字符串 C#【英文标题】:XmlReader creates empty string C# 【发布时间】:2020-01-15 22:51:15 【问题描述】:

我正在使用 StringReader 读取 xml 流,然后我想将该流作为 XML 读取以对其进行序列化和反序列化。 尽管由于某种原因它工作正常,但我的 XmlReader 变量返回 null。 我看到的 XML 和以前一样。

我的代码是:

  StringReader stringReader = new StringReader(result);
        stringReader.ReadLine();//omit the first line that contains xml encoding
        XmlReader xmlReader = XmlReader.Create(stringReader);
        XmlSerializer XmlSerializer = new XmlSerializer(typeof(ResponseDoc));
        ResponseDoc XmlResponseDoc = (ResponseDoc)XmlSerializer.Deserialize(xmlReader);

结果viariable的XML格式是

    <?xml version="1.0" encoding="utf-8"?>
<ResponseDoc xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <response>
    <entitylineNumber>1</entitylineNumber>
    <statusCode>Success</statusCode>
    <entityUid>0BA0C06E9CBAA3D890D025A37A577DDB074BA9A9</entityUid>
    <entityMark>1000000115468</entityMark>
  </response>
</ResponseDoc>

我的 xmlReader 变量为空。我还尝试删除 stringReader.ReadLine();但它没有改变任何东西。 我之所以使用它,是因为如果存在编码行,则无法对其进行序列化。

ResponseDoc 类:

#region XSD Schema
        [XmlRoot(ElementName = "Responses", Namespace = "")]
        public partial class ResponseDoc
        

            private ResponseType[] responseField;

            /// <remarks/>
            [System.Xml.Serialization.XmlElement(ElementName = "Response", Namespace = "")]
            public ResponseType[] response
            
                get
                
                    return this.responseField;
                
                set
                
                    this.responseField = value;
                
            
        

        [XmlRoot(ElementName = "Response", Namespace = "")]
        public partial class ResponseType
        

            private int entitylineNumberField;

            private string statusCodeField;

            private string uid;

            private string markUid;

            private ResponseTypeErrors[] responseTypeErrors;

            /// <remarks/>
            [XmlElement(ElementName = "inv_number", Namespace = "")]
            public string entitylineNumber
            
                get
                
                    return this.entitylineNumberField.ToString();
                
                set
                
                    this.entitylineNumberField = int.Parse(value);
                
            

            /// <remarks/>
            [XmlElement(ElementName = "StatusCode", Namespace = "")]
            public string statusCode
            
                get
                
                    return this.statusCodeField;
                
                set
                
                    this.statusCodeField = value;
                
            

            [XmlElement(ElementName = "Uid", Namespace = "")]
            public string Uid
            
                get
                
                    return this.uid;
                
                set
                
                    this.uid = value;
                
            

            [XmlElement(ElementName = "Mark", Namespace = "")]
            public string Mark
            
                get
                
                    return this.markUid;
                
                set
                
                    this.markUid = value;
                
            
            [XmlElement(ElementName = "Errors", Namespace = "")]
            public ResponseTypeErrors[] Errors
            
                get
                
                    return this.responseTypeErrors;
                
                set
                
                    this.responseTypeErrors = value;
                
            
        

        [XmlRoot(ElementName = "Errors", Namespace = "")]
        public partial class ResponseTypeErrors
        

            private ErrorType[] errorField;

            /// <remarks/>
            [System.Xml.Serialization.XmlElementAttribute("Error")]
            public ErrorType[] error
            
                get
                
                    return this.errorField;
                
                set
                
                    this.errorField = value;
                
            
        

        [XmlRoot(ElementName = "Error", Namespace = "")]
        public partial class ErrorType
        

            private string messageField;

            private int codeField;

            /// <remarks/>
            [XmlElement(ElementName = "Message", Namespace = "")]
            public string message
            
                get
                
                    return this.messageField;
                
                set
                
                    this.messageField = value;
                
            

            /// <remarks/>
            [XmlElement(ElementName = "Code", Namespace = "")]
            public int code
            
                get
                
                    return this.codeField;
                
                set
                
                    this.codeField = value;
                
            

        

        #endregion

更新: 我看到你们所有人都给了我关于我的 XSD 架构的答案。 问题不在于反序列化 XML。 我的问题是

中的变量 xmlReader
XmlReader xmlReader = XmlReader.Create(stringReader);

is None 尽管我在结果变量中有 xml 答案并将其传递给 stringReader。 我不明白为什么有些人在我的问题中给我否定。我相信很清楚我的问题是什么,并且我确信我提供了有关我的代码的足够信息。如果我知道更多,我会自己解决。 我也用 strinReader 和 xmlReader 上传了截图

【问题讨论】:

您是否尝试针对某些在线 XML 验证器验证该 XML?这似乎不正确 @Steve 我无法更改 XML 。它来自外部服务作为答案 如果塞进单个XML文件中是无效的。您确定没有将两个或多个 XML 连接在一起吗?注意你怎么有两个 这在 XML 规范中是不允许的。你只能有一个,而且只能在文件的开头 您的 XML 没有根,解决方法是将服务响应包装在根元素中。例如&lt;ResponseRoot&gt;&lt;/ResponseRoot&gt; @Steve 对不起,你是对的。我粘贴了两次相同的 XML。我编辑我的问题 【参考方案1】:

ElementName 中的每个属性的System.Xml.Serialization.XmlElement 属性必须与 XML 中的元素名称匹配。执行以下操作即可完成修复:

ElementName for ResponseDoc 类应该是 ResponseDoc 而不是 Responses

ResponseDocElementNameresponse 属性应该是response 而不是Response

ResponseDoc 类应如下所示:

[XmlRoot(ElementName = "ResponseDoc", Namespace = "")]
public partial class ResponseDoc


    private ResponseType[] responseField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElement(ElementName = "response", Namespace = "")]
    public ResponseType[] response
    
        get
        
            return this.responseField;
        
        set
        
            this.responseField = value;
        
    

ResponseType 类中确保ElementName 的每个属性都符合XML:

ElementName for entitylineNumber 属性应该是 entitylineNumber 而不是 inv_number

ElementName for statusCode 属性应该是 statusCode 而不是 StatusCode

其他属性的规则如下:

public partial class ResponseType
    
        private int entitylineNumberField;

        private string statusCodeField;

        private string uid;

        private long entityMark;

        [XmlElement(ElementName = "entitylineNumber", Namespace = "")]
        public string entitylineNumber
        
            get
            
                return this.entitylineNumberField.ToString();
            
            set
            
                this.entitylineNumberField = int.Parse(value);
            
        

        /// <remarks/>
        [XmlElement(ElementName = "statusCode", Namespace = "")]
        public string statusCode
        
            get
            
                return this.statusCodeField;
            
            set
            
                this.statusCodeField = value;
            
        

        [XmlElement(ElementName = "entityUid", Namespace = "")]
        public string Uid
        
            get
            
                return this.uid;
            
            set
            
                this.uid = value;
            
        


        [XmlElement(ElementName = "entityMark", Namespace = "")]
        public string EntityMark
        
            get
            
                return this.entityMark.ToString();
            
            set
            
                this.entityMark = long.Parse(value);
            
        
    

【讨论】:

我的问题是在 XmlReader xmlReader = XmlReader.Create(stringReader); xmlReader 为空。之后它不在xml读取中。如果我在 xmlReader 变量中获取数据,一切正常 谢谢,您的代码有效。我还是不明白是什么问题。我的 xmlReader 仍然是 None 但它返回其他变量。怎么会这样?【参考方案2】:

如果您可以使用 Nuget 包,我使用我的开源包 XmlMirror 为您创建了一个解析器。

Install-Package XmlMirror.Runtime -Version 2.2.1

我在此处发布了有关如何制作解析器的视频: https://youtu.be/iGRWDlzVq6s

我将此项目添加为示例项目(希望您不要介意我使用您的 Xml 响应类)。因此,如果您克隆 Xml Mirror,您的示例项目将与它一起安装:

Xml Mirror 的完整代码可在此处获得: https://github.com/DataJuggler/XmlMirror

您的示例代码在这里:

https://github.com/DataJuggler/XmlMirror/tree/master/XmlMirrror/Samples/ResponseLibrary

这是我为解析您的对象而创建的代码(我在我的狗之前醒来并快速编写了这段代码,以向您展示 XmlMirror 是多么简单)。写这篇文章比构建这个项目花费的时间更长。

Xml Mirror 使用反射,所以你必须创建一个类库。

我创建了这个名为 Response.cs 的类:

namespace ResponseLibrary


    #region class Response
    /// <summary>
    /// This class is a response from an API call
    /// </summary>
    public class Response
    

        #region Private Variables
        private int entitylineNumber;
        private string statusCode;
        private string entityUID;
        private string entityMark;
        #endregion

        #region Properties

            #region EntitylineNumber
            /// <summary>
            /// This property gets or sets the value for 'EntitylineNumber'.
            /// </summary>
            public int EntitylineNumber
            
                get  return entitylineNumber; 
                set  entitylineNumber = value; 
            
            #endregion

            #region EntityMark
            /// <summary>
            /// This property gets or sets the value for 'EntityMark'.
            /// </summary>
            public string EntityMark
            
                get  return entityMark; 
                set  entityMark = value; 
            
            #endregion

            #region EntityUID
            /// <summary>
            /// This property gets or sets the value for 'EntityUID'.
            /// </summary>
            public string EntityUID
            
                get  return entityUID; 
                set  entityUID = value; 
            
            #endregion

            #region StatusCode
            /// <summary>
            /// This property gets or sets the value for 'StatusCode'.
            /// </summary>
            public string StatusCode
            
                get  return statusCode; 
                set  statusCode = value; 
            
            #endregion

        #endregion

    
    #endregion

   

接下来安装nuget包XmlMirror.Runtime

这是使用 XmlMirror 创建的解析器类:

解析器使用部分类,所以是一个类,但是两个文件:

ResponsesParser.base.cs

#region using statements

using ResponseLibrary;
using DataJuggler.Core.UltimateHelper;
using System;
using System.Collections.Generic;
using XmlMirror.Runtime.Objects;
using XmlMirror.Runtime.Util;

#endregion

namespace ResponseParserTest.Parsers


    #region class ResponsesParser : ParserBaseClass
    /// <summary>
    /// This class is used to parse 'Response' objects.
    /// </summary>
    public partial class ResponsesParser : ParserBaseClass
    

        #region Methods

            #region ParseResponse(string responseXmlText)
            /// <summary>
            /// This method is used to parse an object of type 'Response'.
            /// </summary>
            /// <param name="responseXmlText">The source xml to be parsed.</param>
            /// <returns>An object of type 'Response'.</returns>
            public Response ParseResponse(string responseXmlText)
            
                // initial value
                Response response = null;

                // if the sourceXmlText exists
                if (TextHelper.Exists(responseXmlText))
                
                    // create an instance of the parser
                    XmlParser parser = new XmlParser();

                    // Create the XmlDoc
                    this.XmlDoc = parser.ParseXmlDocument(responseXmlText);

                    // If the XmlDoc exists and has a root node.
                    if ((this.HasXmlDoc) && (this.XmlDoc.HasRootNode))
                    
                        // Create a new response
                        response = new Response();

                        // Perform preparsing operations
                        bool cancel = Parsing(this.XmlDoc.RootNode, ref response);

                        // if the parsing should not be cancelled
                        if (!cancel)
                        
                            // Parse the 'Response' object
                            response = ParseResponse(ref response, this.XmlDoc.RootNode);

                            // Perform post parsing operations
                            cancel = Parsed(this.XmlDoc.RootNode, ref response);

                            // if the parsing should be cancelled
                            if (cancel)
                            
                                // Set the 'response' object to null
                                response = null;
                            
                        
                    
                

                // return value
                return response;
            
            #endregion

            #region ParseResponse(ref Response response, XmlNode xmlNode)
            /// <summary>
            /// This method is used to parse Response objects.
            /// </summary>
            public Response ParseResponse(ref Response response, XmlNode xmlNode)
            
                // if the response object exists and the xmlNode exists
                if ((response != null) && (xmlNode != null))
                
                    // get the full name of this node
                    string fullName = xmlNode.GetFullName();

                    // Check the name of this node to see if it is mapped to a property
                    switch(fullName)
                    
                        case "ResponseDoc.response.entitylineNumber":

                            // Set the value for response.EntitylineNumber
                            response.EntitylineNumber = NumericHelper.ParseInteger(xmlNode.FormattedNodeValue, 0, -1);

                            // required
                            break;

                        case "ResponseDoc.response.entityMark":

                            // Set the value for response.EntityMark
                            response.EntityMark = xmlNode.FormattedNodeValue;

                            // required
                            break;

                        case "ResponseDoc.response.entityUid":

                            // Set the value for response.EntityUID
                            response.EntityUID = xmlNode.FormattedNodeValue;

                            // required
                            break;

                        case "ResponseDoc.response.statusCode":

                            // Set the value for response.StatusCode
                            response.StatusCode = xmlNode.FormattedNodeValue;

                            // required
                            break;

                    

                    // if there are ChildNodes
                    if (xmlNode.HasChildNodes)
                    
                        // iterate the child nodes
                         foreach(XmlNode childNode in xmlNode.ChildNodes)
                        
                            // append to this Response
                            response = ParseResponse(ref response, childNode);
                        
                    
                

                // return value
                return response;
            
            #endregion

        #endregion

    
    #endregion


ResponsesParser.custom.cs

#region using statements

using ResponseLibrary;
using XmlMirror.Runtime.Objects;

#endregion

namespace ResponseParserTest.Parsers


    #region class ResponsesParser : ParserBaseClass
    /// <summary>
    /// This class is used to parse 'Response' objects.
    /// </summary>
    public partial class ResponsesParser : ParserBaseClass
    

        #region Events

            #region Parsing(XmlNode xmlNode)
            /// <summary>
            /// This event is fired BEFORE the collection is initialized.
            /// </summary>
            /// <param name="xmlNode"></param>
            /// <returns>True if cancelled else false if not.</returns>
            public bool Parsing(XmlNode xmlNode)
            
                // initial value
                bool cancel = false;

                // Add any pre processing code here. Set cancel to true to abort parsing this collection.

                // return value
                return cancel;
            
            #endregion

            #region Parsing(XmlNode xmlNode, ref Response response)
            /// <summary>
            /// This event is fired when a single object is initialized.
            /// </summary>
            /// <param name="xmlNode"></param>
            /// <param name="response"></param>
            /// <returns>True if cancelled else false if not.</returns>
            public bool Parsing(XmlNode xmlNode, ref Response response)
            
                // initial value
                bool cancel = false;

                // Add any pre processing code here. Set cancel to true to abort adding this object.

                // return value
                return cancel;
            
            #endregion

            #region Parsed(XmlNode xmlNode, ref Response response)
            /// <summary>
            /// This event is fired AFTER the response is parsed.
            /// </summary>
            /// <param name="xmlNode"></param>
            /// <param name="response"></param>
            /// <returns>True if cancelled else false if not.</returns>
            public bool Parsed(XmlNode xmlNode, ref Response response)
            
                // initial value
                bool cancel = false;

                // Add any post processing code here. Set cancel to true to abort adding this object.

                // return value
                return cancel;
            
            #endregion

        #endregion

    
    #endregion


然后要使用解析器,你要做的就是这样:

(我正在使用按钮单击,因为我编写了一个快速的 Windows 窗体来测试它):

    // xml
    string xml = File.ReadAllText(labelTextBoxBrowserControl1.Text);

    // Create a new instance of a 'ResponsesParser' object.
    ResponsesParser parser = new ResponsesParser();

    // load the response
    Response response = parser.ParseResponse(xml);

    // if the response object exists
    if (response != null)
       
        // set each property from the response
        EntityLineNumberControl.Text = response.EntitylineNumber.ToString();
        EntityUIDControl.Text = response.EntityUID;
        StatusCodeControl.Text = response.StatusCode;
        EntityMarkControl.Text = response.EntityMark;
    

以前,我在编写 Xml Mirror 时必须将解析 Xml 作为我的主要工作之一。

它也解析集合,但我没有为这个例子构建一个。

【讨论】:

我的问题是在 XmlReader xmlReader = XmlReader.Create(stringReader); xmlReader 为空。之后它不在xml读取中。如果我在 xmlReader 变量中获取数据,一切正常 感谢您的宝贵时间。我看到了你的视频和你的代码。我肯定会更彻底地检查它,因为如果您使用 XML 数据,它似乎很有希望。现在@Rashid Ali 代码工作正常

以上是关于XmlReader 创建空字符串 C#的主要内容,如果未能解决你的问题,请参考以下文章

C# 将 char* 编组到 StringBuilder 总是得到空字符串

数据结构与算法(C#)入门 --- 串和数组

C# 正则表达式拆分但如果拆分失败则包含空字符串

尝试从 WinJS 读取 C# WinRT 组件中的空字符串时出现异常

如何判断既不为null也不为空字符串

合并与空字符串连接