如果数据在一行上
elif ... else
和
if
使光标向前移动。如果我接受这些调用,我会在调试中看到它循环6次。
在下面的第一个(index=int.Parse(logDataReader.ReadElementContentAsString());
)中只读取了3个value=double.Parse(logDataReader.ReadElementContentAsString(),
(并且它们的值是下一个索引的值)。在第二个(<data>
)上读取所有<logData id="Bravo">
。
不能选择编辑xml并放入换行符,因为该文件是动态创建的(通过XMLwriter)。 <logData id="Bravo">
设置是换行符。从XMLwriter开始,它实际上只是一行 - 我把它分解出来以确定它在哪里破碎。在浏览器中显示正确。
如何解决此问题?
这是我的XML:
<data>
我的代码:
NewLineChars
答案 0 :(得分:4)
您的问题如下。根据{{1}}的{{3}}:
此方法读取开始标记,元素的内容,并将读者移动过去结束元素标记。
来自XmlReader.ReadElementContentAsString()
的{{3}}:
它使读者前进到与指定名称匹配的 next 跟随元素,如果找到匹配的元素则返回true。
因此,在调用XmlReader.ReadToFollowing(String)
之后,由于读者已进入下一个节点,因此它可能已经位于下一个ReadElementContentAsString()
或<value>
节点上。然后,当您致电<data>
时,此元素节点被跳过,因为该方法无条件地移动到具有正确名称的 next 节点。但是如果XML是缩进的,那么在调用ReadToFollowing()
之后的下一个节点将是ReadElementContentAsString()
节点,以防止此错误。
解决方法是在调用XmlNodeType.Whitespace
后检查阅读器是否已正确定位。首先,介绍以下扩展方法:
ReadElementContentAsString()
然后按如下方式修改您的代码:
public static class XmlReaderExtensions
{
public static bool ReadToFollowingOrCurrent(this XmlReader reader, string localName, string namespaceURI)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
if (reader.NodeType == XmlNodeType.Element && reader.LocalName == localName && reader.NamespaceURI == namespaceURI)
return true;
return reader.ReadToFollowing(localName, namespaceURI);
}
}
注意:
始终更喜欢使用public static List<LogData> GetLogDatasFromFile(string xmlFile)
{
List<LogData> logDatas = new List<LogData>();
using (XmlReader reader = XmlReader.Create(xmlFile))
{
// move to next "logData"
while (reader.ReadToFollowing("logData", ""))
{
var logData = new LogData(reader.GetAttribute("id"));
using (var logDataReader = reader.ReadSubtree())
{
// inside "logData" subtree, move to next "data"
while (logDataReader.ReadToFollowing("data", ""))
{
// move to index
logDataReader.ReadToFollowing("index", "");
// read index
var index = XmlConvert.ToInt32(logDataReader.ReadElementContentAsString());
// move to value
logDataReader.ReadToFollowingOrCurrent("value", "");
// read value
var value = XmlConvert.ToDouble(logDataReader.ReadElementContentAsString());
logData.LogPoints.Add(new LogPoint(index, value));
}
}
logDatas.Add(logData);
}
}
return logDatas;
}
方法,其中单独指定本地名称和命名空间,例如documentation。当您使用接受单个限定名称的documentation等方法时,您隐式硬编码XML 前缀的选择,这通常不是一个好主意。 XML解析应独立于前缀选择。
在使用XmlReader
语言环境正确解析双精度语时,使用XmlReader.ReadToFollowing (String, String)
类中的方法更容易正确处理解析和格式化。
XmlReader.ReadToFollowing(String)
将CultureInfo.InvariantCulture
位于位于正在读取的元素的XmlReader
节点上,因此您无需拨打电话之后EndElement
。 (很好地使用ReadToFollowingOrCurrent()
来避免读取太少或太多;通过使用此方法,可以避免使用ReadSubtree()
的几个常见错误。)
正如您所发现的那样,使用XmlReader
手动读取XML的代码应该始终使用格式化和未格式化的XML进行单元测试,因为某些错误只会出现在一个或另一个错误中。 (例如,请参阅XmlConvert
,XmlReader.ReadSubtree()
和this answer等其他示例。)
工作样本.Net小提琴this one。
答案 1 :(得分:1)
事实上,我在另一个问题中提供的代码是错误的。 ReadToFollowing
将使用此名称读取下一个元素,即使它的光标已经位于具有此名称的元素上。当有空格时 - 在您阅读index
之后,光标移动到该空白并且ReadToFollowing("value")
按预期工作。但是,如果没有空格,则游标已经在value
节点上,因此ReadToFollowing("value")
将读取后续“数据”节点中的下一个“值”。
我认为以下是一种更安全的方法:
public static List<LogData> GetLogDatasFromFile(string xmlFile) {
List<LogData> logDatas = new List<LogData>();
using (XmlReader reader = XmlReader.Create(xmlFile)) {
LogData currentData = null;
while (reader.Read()) {
if (reader.IsStartElement("logData")) {
// we are positioned on start of logData
if (currentData != null)
logDatas.Add(currentData);
currentData = new LogData(reader.GetAttribute("id"));
}
else if (reader.IsStartElement("data")) {
// we are on start of "data"
// we always have "currentData" at this point
Debug.Assert(currentData != null);
reader.ReadToFollowing("index");
var index = int.Parse(reader.ReadElementContentAsString());
// check if we are not already on "value"
if (!reader.IsStartElement("value"))
reader.ReadToFollowing("value");
var value = double.Parse(reader.ReadElementContentAsString(), CultureInfo.InvariantCulture);
currentData.LogPoints.Add(new LogPoint(index, value));
}
}
if (currentData != null)
logDatas.Add(currentData);
}
return logDatas;
}
答案 2 :(得分:0)
我发现了一个修复但对我来说不是一个可接受的答案。对于换行符,XMLreader的行为不应该不同。
在XmlWriter
中,这会在文字中添加换行符:
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.NewLineOnAttributes = true;
xmlWriterSettings.Indent = true;
using (XmlWriter xmlWriter = XmlWriter.Create(fileNameXML, xmlWriterSettings))
{
我发现了here。