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。 我的问题是
中的变量 xmlReaderXmlReader xmlReader = XmlReader.Create(stringReader);
is None 尽管我在结果变量中有 xml 答案并将其传递给 stringReader。 我不明白为什么有些人在我的问题中给我否定。我相信很清楚我的问题是什么,并且我确信我提供了有关我的代码的足够信息。如果我知道更多,我会自己解决。 我也用 strinReader 和 xmlReader 上传了截图
【问题讨论】:
您是否尝试针对某些在线 XML 验证器验证该 XML?这似乎不正确 @Steve 我无法更改 XML 。它来自外部服务作为答案 如果塞进单个XML文件中是无效的。您确定没有将两个或多个 XML 连接在一起吗?注意你怎么有两个 这在 XML 规范中是不允许的。你只能有一个,而且只能在文件的开头 您的 XML 没有根,解决方法是将服务响应包装在根元素中。例如<ResponseRoot></ResponseRoot>
@Steve 对不起,你是对的。我粘贴了两次相同的 XML。我编辑我的问题
【参考方案1】:
ElementName
中的每个属性的System.Xml.Serialization.XmlElement
属性必须与 XML 中的元素名称匹配。执行以下操作即可完成修复:
ElementName
for ResponseDoc
类应该是 ResponseDoc 而不是 Responses
在ResponseDoc
类ElementName
中response
属性应该是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 总是得到空字符串