XMLReader换行符使用\n而不是\r\n

16

当我使用XmlReader.ReadOuterXml()时,元素之间以\n分隔而不是\r\n。例如,如果我有一个XmlDocument表征

<A>
<B>
</B>
</A>

我收到了

<A>\n<B>\n</B>\n</A>

是否有指定换行符的选项?XmlWriterSettings 有,但 XmlReader 似乎没有。

这是我读取 XML 的代码。注意,默认情况下,XmlWriterSettings 具有 NewLineHandling = Replace。

XmlDocument xmlDocument = <Generate some XmlDocument>
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;

// Use a memory stream because it accepts UTF8 characters.  If we use a 
// string builder the XML will be UTF16.
using (MemoryStream memStream = new MemoryStream())
{
    using (XmlWriter xmlWriter = XmlWriter.Create(memStream, settings))
    {
        xmlDocument.Save(xmlWriter);
    }

    //Set the pointer back to the beginning of the stream to be read
    memStream.Position = 0;
    using (XmlReader reader = XmlReader.Create(memStream))
    {
        reader.Read();
        string header = reader.Value;
        reader.MoveToContent();
        return "<?xml " + header + " ?>" + Environment.NewLine + reader.ReadOuterXml();
    }
}

当输入的XML混合了\r\n和\n时,这会进一步增加麻烦,而且当下游系统对两者之间的差异敏感时,例如XML文档是在执行XSLT转换之前处于中间状态,然后将输出编码为具有特定分隔符的平面文件。 - David Burg
5个回答

17

1
为了实现跨平台兼容性,我建议使用.Replace("\n", Environment.NewLine),但如果您的环境固定不变,这个功能是完全相同的。 - Flynn1179

5
我需要将数据库数据写入XML文件,并使用LINQ to XML从XML文件中读取,记录中的一些字段本身是包含\r字符的完整XML字符串。这些必须保持不变。我花了几天时间寻找能够起作用的解决方案,但似乎微软设计上将\r转换为\n。
下面的解决方案适用于我: 要将已加载的XDocument保留\r的方式写入XML文件,其中xDoc是XDocument并且filePath是一个字符串:
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings 
    { NewLineHandling = NewLineHandling.None, Indent = true };
using (XmlWriter xmlWriter = XmlWriter.Create(filePath, xmlWriterSettings))
{
    xDoc.Save(xmlWriter);
    xmlWriter.Flush();
}

将一个XML文件读入XElement,保留 \r 标识:

using (XmlTextReader xmlTextReader = new XmlTextReader(filePath) 
   { WhitespaceHandling = WhitespaceHandling.Significant })
{
     xmlTextReader.MoveToContent();
     xDatabaseElement = XElement.Load(xmlTextReader);
}

1
这是因为XmlTextReader的规范化设置默认为false,而XmlReader.Create始终规范化换行符,无论如何。请参见https://msdn.microsoft.com/en-us/library/system.xml.xmltextreader.normalization(v=vs.110).aspx和https://msdn.microsoft.com/en-us/library/system.xml.xmlwritersettings.newlinehandling(v=vs.110).aspx末尾的注释。 - David Burg

3

解决方案1:编写实体化的XML

使用配置良好的 XmlWriter,并使用NewLineHandling.Entitize选项,这样XmlReader就不会将行尾标准化。

即使是与XDocument一起使用,也可以使用这样的自定义XmlWriter

xDoc.Save(XmlWriter.Create(fileName, new XmlWriterSettings { NewLineHandling = NewLineHandling.Entitize }));

解决方法2:读取未实体化的XML,不进行规范化

解决方法1是更为清晰的方式;但是,你可能已经有了未实体化的XML,无法修改创建方式,同时又想防止规范化。接受的答案建议使用替换,但是这种方法会盲目替换每个\n出现,即使不需要也会被替换。为了按照文件中原样检索所有换行符号,可以尝试使用传统的XmlTextReader类,默认情况下该类不对XML文件进行规范化。你也可以将它与XDocument一起使用:

var xDoc = XDocument.Load(new XmlTextReader(fileName));

0

如果你只是想转换成UTF-8,有一个更快的方法。首先创建一个writer:

public class EncodedStringWriter : StringWriter
{
    public EncodedStringWriter(StringBuilder sb, Encoding encoding)
        : base(sb)
    {
        _encoding = encoding;
    }

    private Encoding _encoding;

    public override Encoding Encoding
    {
        get
        {
            return _encoding;
        }
    }

}

然后使用它:

XmlDocument doc = new XmlDocument();
doc.LoadXml("<foo><bar /></foo>");

StringBuilder sb = new StringBuilder();
XmlWriterSettings xws = new XmlWriterSettings();
xws.Indent = true;

using( EncodedStringWriter w = new EncodedStringWriter(sb, Encoding.UTF8) )
{
    using( XmlWriter writer = XmlWriter.Create(w, xws) )
    {
        doc.WriteTo(writer);
    }
}
string xml = sb.ToString();

必须要给应得的荣誉


-2

XmlReader 用于读取文件,而不是写入文件。如果您在读取器中获取了 \n,则是因为文件中存在该字符。在 XML 中,\n 和 \r 都是空格,语义上相同,不会影响数据的含义或内容。

编辑:

看起来这是 C#,而不是 Ruby。如 binarycoder 所说,ReadOuterXml 被定义为返回规范化的 XML。通常这就是您想要的。如果您想要原始的 XML,则应使用 Encoding.UTF8.GetString(memStream.ToArray()),而不是 XmlReader


抱歉,我添加了我的代码。如果我使用 NewLineHandling = Replace 的 XmlWriter,它不应该会写出正确的字符串吗? - user156144

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接