我有一个简单的xml
<data>
<node1>value1</node1>
<node2>value2</node2>
</data>
我正在使用IXmlSerializable来读取和编写带有DTO的xml。以下代码可以正常使用
XmlReader reader;
...
while( reader.Read() ){
Console.Write( reader.ReadElementContentAsString() );
}
// outputs value1value2
但是,如果xml中的空格被删除,即
<data>
<node1>value1</node1><node2>value2</node2>
</data>
或者我使用XmlReaderSettings.IgnoreWhitespace = true;
,代码只输出“value1”忽略第二个节点。当我打印解析器遍历的节点时,我可以看到ReadElementContentAsString
将指针移动到EndElement
的{{1}},但我不明白为什么会发生这种情况或如何解决它。
这是一个可能的XML解析器实现错误吗?
===============================================
这是一个示例代码和2个xml样本,可以产生不同的结果
node2
1。)settings.xml
string homedir = Path.GetDirectoryName(Application.ExecutablePath);
string xml = Path.Combine( homedir, "settings.xml" );
FileStream stream = new FileStream( xml, FileMode.Open );
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreWhitespace = false;
XmlReader reader = XmlTextReader.Create( stream, readerSettings );
while( reader.Read() ){
if ( reader.MoveToContent() == XmlNodeType.Element && reader.Name != "data" ){
System.Diagnostics.Trace.WriteLine(
reader.NodeType
+ " "
+ reader.Name
+ " "
+ reader.ReadElementContentAsString()
);
}
}
stream.Close();
2。)settings.xml
<?xml version="1.0"?>
<data>
<node-1>value1</node-1>
<node-2>value2</node-2>
</data>
使用(1)打印
<?xml version="1.0"?>
<data>
<node-1>value1</node-1><node-2>value2</node-2>
</data>
使用(2)打印
Element node-1 value1
Element node-2 value2
答案 0 :(得分:3)
根据IgnoreWhitespace的文档,新行不被认为是无关紧要的。
不被视为重要的空格包括空格,制表符和空行,用于分隔标记以提高可读性。一个例子是元素内容中的空格。
答案 1 :(得分:1)
reader.Read()
读取空格字符时会发生这种情况。忽略空格,相同的指令读取第二个元素(“gnam”一个XML标记),确实将指针带到 node2 元素。
在示例中调用的方法之前和之后调试reader
属性。检查 NodeType 和 Value 属性。还要检查 MoveToContent 方法,它非常有用。
阅读所有方法和属性的文档,最后您将了解 XmlReader 类的工作原理,以及如何将它用于您的目的。 Here是第一个google结果:它包含一个非常明确的示例。
我最终得到以下(不完整)模式:
private static void ReadXmlExt(XmlReader xmlReader, IXmlSerializableExt xmlSerializable, ReadElementDelegate readElementCallback)
{
bool isEmpty;
if (xmlReader == null)
throw new ArgumentNullException("xmlReader");
if (readElementCallback == null)
throw new ArgumentNullException("readElementCallback");
// Empty element?
isEmpty = xmlReader.IsEmptyElement;
// Decode attributes
if ((xmlReader.HasAttributes == true) && (xmlSerializable != null))
xmlSerializable.ReadAttributes(xmlReader);
// Read the root start element
xmlReader.ReadStartElement();
// Decode elements
if (isEmpty == false) {
do {
// Read document till next element
xmlReader.MoveToContent();
if (xmlReader.NodeType == XmlNodeType.Element) {
string elementName = xmlReader.LocalName;
// Empty element?
isEmpty = xmlReader.IsEmptyElement;
// Decode child element
readElementCallback(xmlReader);
xmlReader.MoveToContent();
// Read the child end element (not empty)
if (isEmpty == false) {
// Delegate check: it has to reach and end element
if (xmlReader.NodeType != XmlNodeType.EndElement)
throw new InvalidOperationException(String.Format("not reached the end element"));
// Delegate check: the end element shall correspond to the start element before delegate
if (xmlReader.LocalName != elementName)
throw new InvalidOperationException(String.Format("not reached the relative end element of {0}", elementName));
// Child end element
xmlReader.ReadEndElement();
}
} else if (xmlReader.NodeType == XmlNodeType.Text) {
if (xmlSerializable != null) {
// Interface
xmlSerializable.ReadText(xmlReader);
Debug.Assert(xmlReader.NodeType != XmlNodeType.Text, "IXmlSerializableExt.ReadText shall read the text");
} else
xmlReader.Skip(); // Skip text
}
} while (xmlReader.NodeType != XmlNodeType.EndElement);
}
}
答案 2 :(得分:1)
这并不像Luca的回答那么强大,但我发现以下模式对合理的'可预测'XML有用(仅限空白和值的变化)。考虑:
string homedir = Path.GetDirectoryName(Application.ExecutablePath);
string xml = Path.Combine( homedir, "settings.xml" );
FileStream stream = new FileStream( xml, FileMode.Open );
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.IgnoreWhitespace = false;
XmlReader reader = XmlTextReader.Create( stream, readerSettings );
while( reader.Read() ){
if ( reader.MoveToContent() == XmlNodeType.Element && reader.Name != "data" ){
string name = reader.Name;
string value = null;
if (!reader.IsEmptyElement)
{
reader.Read(); // advances reader to element content
value = reader.ReadContentAsString(); // advances reader to endelement
}
reader.Read(); // advance reader to element content
System.Diagnostics.Trace.WriteLine(
reader.NodeType
+ " "
+ name
+ " "
+ value
);
}
}
stream.Close();
更一般地,代替reader.ReadElementContent*()
,使用reader.Read()
后跟reader.ReadContent*()
。
答案 3 :(得分:1)
如果您希望XmlReader不读取空格,则应使用以下设置初始化XmlReader:
<div class="container">
<div id="left">This is my left outer div</div>
<div id="middle">This is my middle div</div>
<div id="right">This is my right outer div</div>
</div>
它适用于我发布的结构的xml文件:
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreWhitespace = true;
XmlReader xrd = XmlReader.Create(@"file.xml", settings);