【问题标题】:c# whitespaces issue with XmlReaderc# XmlReader 的空格问题
【发布时间】:2012-02-22 17:25:38
【问题描述】:

我有一个简单的 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 将指针移动到node2EndElement,但我不明白为什么会发生这种情况或如何解决它。

这可能是 XML 解析器实现的错误吗?

================================================

这是一个示例代码和 2 个产生不同结果的 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(); 

1.) settings.xml

<?xml version="1.0"?>
<data>
    <node-1>value1</node-1>
    <node-2>value2</node-2>
</data>

2.) settings.xml

<?xml version="1.0"?>
<data>
    <node-1>value1</node-1><node-2>value2</node-2>
</data>

使用 (1) 个打印件

Element node-1 value1
Element node-2 value2

使用 (2) 个打印件

Element node-1 value1

【问题讨论】:

  • 您能否发布一个小而完整的示例来重现该问题?这似乎是无效的代码,很难判断出了什么问题。
  • 好的,[this][1] 说明问题[1]:stackoverflow.com/questions/2299632/…

标签: c# xmlreader


【解决方案1】:

根据 IgnoreWhitespace 上的文档,新行不被视为无关紧要。

不重要的空白包括用于分隔标记以提高可读性的空格、制表符和空白行。元素内容中的空白就是一个例子。

XmlReaderSettings.IgnoreWhitespace

【讨论】:

  • 有道理,但如果我设置XmlReaderSettings.IgnoreWhitespace = true;,即使是第一个xml也无法正确解析
【解决方案2】:

碰巧reader.Read() 读取了空白字符。忽略空格,相同的指令读取第二个元素(“gnam”一个 XML 标记),确实将指针指向 node2 元素。

在示例中调用的方法之前和之后调试 reader 属性。检查 NodeTypeValue 属性。也检查一下 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);
    }
}

【讨论】:

    【解决方案3】:

    这并不像 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*()

    【讨论】:

      【解决方案4】:

      如果您希望 XmlReader 不读取空格,则应使用以下设置初始化 XmlReader:

      XmlReaderSettings settings = new XmlReaderSettings();
      settings.IgnoreWhitespace = true;
      XmlReader xrd = XmlReader.Create(@"file.xml", settings);
      

      它在您发布的结构的 xml 文件中对我有用:

      <data>
          <node1>value1</node1>
          <node2>value2</node2>
      </data>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-08
        • 1970-01-01
        • 2020-01-15
        • 1970-01-01
        相关资源
        最近更新 更多