我需要将对象序列化为XML文件,但有一些格式限制:
我编写的以下代码负责限制1和2:
public void WriteToXml(TextWriter writer)
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
using (XmlWriter xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = true, Indent = true, IndentChars = "\t" }))
{
new XmlSerializer(typeof(CalledUnit)).Serialize(xmlWriter, this, ns);
}
}
并获得以下结果:
<CalledUnit>
<Caller>some info</Caller>
<CallerId>1001</CallerId>
<Called>some more info</Called>
<CalledId>31</CalledId>
</CalledUnit>
但我想要以下结果(注意缩进):
<CalledUnit>
<Caller>some info</Caller>
<CallerId>1001</CallerId>
<Called>some more info</Called>
<CalledId>31</CalledId>
</CalledUnit>
有任何想法如何解决这个问题?
答案 0 :(得分:1)
如果文件不大,您可以序列化为内存流,然后逐行从流中读取并将其写入文件,同时为前缀添加所需的空格缩进。如果您需要代码示例,请注释。
答案 1 :(得分:1)
首先,这不是一个真正的XML问题 - XML并不真正关心这样的空白问题。
但是,你可以通过自己进行格式化来实现这一点。在WriteToXml
方法中,不要直接写入TextWriter
,而是写信给StringBuilder
,然后在字符串上运行正则表达式,将\r\n
替换为\r\n
+要填充它的空格数。或者,您可以使用StringReader.ReadLine()
之类的内容阅读您的信息流,并将其输出(由您的空格预先添加)写入TextWriter
。
答案 2 :(得分:0)
使用.Net XML类没有明显的方法可以做到这一点。 (例如,XmlTextWriter.Indent()
不是虚拟的,如reference source所示。)您可能需要将XML流式传输到中间表示中,然后对其进行修补。但是,您可以使用来自CDATA nodes的Mark Fussell WriteShallowNode
进行修补,而不是使用正则表达式进行修补(可能会导致Combining the XmlReader and XmlWriter classes for simple streaming transformations出现问题):
public void WriteToXml(TextWriter writer)
{
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent = true, IndentChars = "\t" };
string xml;
using (var tempWriter = new StringWriter())
{
using (XmlWriter xmlWriter = XmlWriter.Create(tempWriter, settings))
new XmlSerializer(this.GetType()).Serialize(xmlWriter, this, ns);
xml = tempWriter.ToString();
}
using (var reader = new StringReader(xml))
using (var xmlReader = XmlReader.Create(reader))
{
XmlNodeType? prevType = null;
using (var xmlWriter = XmlWriter.Create(writer, settings))
{
while (xmlReader.Read())
{
if ((xmlReader.NodeType == XmlNodeType.Element || xmlReader.NodeType == XmlNodeType.EndElement)
&& (prevType == null || prevType == XmlNodeType.Whitespace))
{
xmlWriter.WriteWhitespace(settings.IndentChars); // Add one more indentation
}
xmlWriter.WriteShallowNode(xmlReader);
prevType = xmlReader.NodeType;
}
}
}
}
然后,将Mark Fussell的代码改编为扩展方法:
public static class XmlWriterExtensions
{
public static void WriteShallowNode(this XmlWriter writer, XmlReader reader)
{
// adapted from http://blogs.msdn.com/b/mfussell/archive/2005/02/12/371546.aspx
if (reader == null)
throw new ArgumentNullException("reader");
if (writer == null)
throw new ArgumentNullException("writer");
switch (reader.NodeType)
{
case XmlNodeType.Element:
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
writer.WriteAttributes(reader, true);
if (reader.IsEmptyElement)
{
writer.WriteEndElement();
}
break;
case XmlNodeType.Text:
writer.WriteString(reader.Value);
break;
case XmlNodeType.Whitespace:
case XmlNodeType.SignificantWhitespace:
writer.WriteWhitespace(reader.Value);
break;
case XmlNodeType.CDATA:
writer.WriteCData(reader.Value);
break;
case XmlNodeType.EntityReference:
writer.WriteEntityRef(reader.Name);
break;
case XmlNodeType.XmlDeclaration:
case XmlNodeType.ProcessingInstruction:
writer.WriteProcessingInstruction(reader.Name, reader.Value);
break;
case XmlNodeType.DocumentType:
writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
break;
case XmlNodeType.Comment:
writer.WriteComment(reader.Value);
break;
case XmlNodeType.EndElement:
writer.WriteFullEndElement();
break;
default:
Debug.WriteLine("unknown NodeType " + reader.NodeType);
break;
}
}
}