如何自定义XmlWriter的序列化输出以移除空元素末尾的空格?
如何自定义XmlWriter的序列化输出以移除空元素末尾的空格?
碰到这种内部类没法直接继承修改的情况确实头疼,不过有两个实用的办法能解决空元素末尾带空格的问题,给你详细说说:
方法一:直接处理生成后的字符串
因为你是用StringBuilder来存储XML输出的,这种方法最简单粗暴——等XmlWriter写完所有内容后,直接对生成的字符串做替换,把所有的 />替换成/>就行:
// 在XmlWriter完成写入操作后执行 string finalXml = sbXmlDoc.ToString().Replace(" />", "/>");
这种方案适合场景简单的情况,一般XML里不会出现文本节点包含 />的情况,所以不用担心误替换的问题。
方法二:包装XmlWriter自定义空元素输出
如果不想做字符串替换,也可以写一个自定义的XmlWriter包装类,把所有操作转发给原有的XmlWriter,只重写WriteEndElement方法来控制空元素的输出格式:
首先定义这个包装类:
public class CustomXmlWriter : XmlWriter { private readonly XmlWriter _innerWriter; private bool _isEmptyElement; public CustomXmlWriter(XmlWriter innerWriter) { _innerWriter = innerWriter; } public override void WriteStartElement(string prefix, string localName, string ns) { // 标记当前元素初始状态为“空元素” _isEmptyElement = true; _innerWriter.WriteStartElement(prefix, localName, ns); } // 只要元素内写入了内容,就标记为非空元素 public override void WriteString(string text) { _isEmptyElement = false; _innerWriter.WriteString(text); } public override void WriteEndElement() { if (_isEmptyElement) { // 空元素直接输出不带空格的闭合标签 _innerWriter.WriteRaw("/>"); _isEmptyElement = false; } else { // 非空元素按正常逻辑处理 _innerWriter.WriteEndElement(); } } // 以下是必须重写的XmlWriter抽象方法,全部转发给内部的XmlWriter即可 public override void Flush() => _innerWriter.Flush(); public override string LookupPrefix(string ns) => _innerWriter.LookupPrefix(ns); public override void WriteBase64(byte[] buffer, int index, int count) => _innerWriter.WriteBase64(buffer, index, count); public override void WriteCData(string text) => _innerWriter.WriteCData(text); public override void WriteCharEntity(char ch) => _innerWriter.WriteCharEntity(ch); public override void WriteChars(char[] buffer, int index, int count) => _innerWriter.WriteChars(buffer, index, count); public override void WriteComment(string text) => _innerWriter.WriteComment(text); public override void WriteDocType(string name, string pubid, string sysid, string subset) => _innerWriter.WriteDocType(name, pubid, sysid, subset); public override void WriteEndDocument() => _innerWriter.WriteEndDocument(); public override void WriteEntityRef(string name) => _innerWriter.WriteEntityRef(name); public override void WriteFullEndElement() => _innerWriter.WriteFullEndElement(); public override void WriteProcessingInstruction(string name, string text) => _innerWriter.WriteProcessingInstruction(name, text); public override void WriteRaw(string data) => _innerWriter.WriteRaw(data); public override void WriteRaw(char[] buffer, int index, int count) => _innerWriter.WriteRaw(buffer, index, count); public override void WriteStartAttribute(string prefix, string localName, string ns) => _innerWriter.WriteStartAttribute(prefix, localName, ns); public override void WriteStartDocument(bool standalone) => _innerWriter.WriteStartDocument(standalone); public override void WriteStartDocument() => _innerWriter.WriteStartDocument(); public override void WriteSurrogateCharEntity(char lowChar, char highChar) => _innerWriter.WriteSurrogateCharEntity(lowChar, highChar); public override void WriteWhitespace(string ws) => _innerWriter.WriteWhitespace(ws); public override XmlWriterSettings Settings => _innerWriter.Settings; public override WriteState WriteState => _innerWriter.WriteState; public override XmlSpace XmlSpace => _innerWriter.XmlSpace; }
然后使用的时候,把原本创建的XmlWriter包装起来就行:
XmlWriter innerWriter = XmlWriter.Create(sbXmlDoc, new XmlWriterSettings { Indent = true, IndentChars = " ", OmitXmlDeclaration = true }); using (var customWriter = new CustomXmlWriter(innerWriter)) { // 这里用customWriter来完成你的XML写入操作 // 示例: // customWriter.WriteStartElement("root"); // customWriter.WriteStartElement("emptyElement"); // customWriter.WriteEndElement(); // customWriter.WriteEndElement(); }
这种方法更灵活,也避免了字符串替换的潜在风险,适合复杂的XML生成场景。
另外提一句:虽然XmlTextWriter现在不推荐使用,但如果你的场景特别简单,也可以试试它——它默认输出的空元素就是不带空格的/>,不过还是更推荐上面两种符合官方XmlWriter.Create规范的方案。
备注:内容来源于stack exchange,提问作者Jez
相关产品推荐
相关产品推荐

