如何移除XML结束标签前最后一个属性后的空格?
问题与解决方案
问题描述
我用System.Xml.Linq生成XML时,遇到一个细节问题:自闭合元素的最后一个属性引号和/>之间会多出一个空格。比如实际生成的是:
<Organization Name="1" ContractDate="2024-02-27T00:00:00Z" />
但我需要的是:
<Organization Name="1" ContractDate="2024-02-27T00:00:00Z"/>
试过用xdoc.Save(path, SaveOptions.DisableFormatting),但这会把整个XML压缩成单行,删掉所有空格,不符合我的需求——我只需要移除最后一个属性和/>之间的那一个空格。
当前使用的代码:
XDocument xdoc = new XDocument(); XElement organization = new XElement("Organization"); XAttribute organizationContractDateAttr = new XAttribute("ContractDate", (inputData.OrganizationData.ContractDate).ToString("yyyy-MM-ddT00:00:00Z")); organization.Add(organizationInnAttr, organizationKppAttr, organizationNameAttr, organizationGozuidAttr, organizationContractDateAttr); xdoc.Save(path);
解决方案
方案1:简单文本替换(适合大多数场景)
如果你的XML内容里不会出现" />"作为文本内容(比如CDATA块、元素文本中),可以先正常生成带格式的XML,再替换掉所有自闭合标签的空格。代码简单易实现:
// 配置XML格式化参数,保持正常缩进和属性排版 var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = false, // 根据你的需求调整是否保留XML声明 NewLineOnAttributes = false // 让所有属性保持在同一行 }; using (var stringWriter = new StringWriter()) using (var xmlWriter = XmlWriter.Create(stringWriter, settings)) { xdoc.Save(xmlWriter); // 替换所有自闭合标签的" />"为"/>" var processedXml = stringWriter.ToString().Replace(" />", "/>"); // 写入文件 File.WriteAllText(path, processedXml); }
方案2:自定义XmlWriter(严谨无风险)
如果需要避免误替换(比如XML文本中可能出现" />"),可以自定义一个XmlWriter来精准控制自闭合标签的输出格式。这种方式更严谨,但代码量稍大:
public class NoTrailingSpaceXmlWriter : XmlWriter { private readonly XmlWriter _innerWriter; private bool _isSelfClosingElement; public NoTrailingSpaceXmlWriter(XmlWriter innerWriter) { _innerWriter = innerWriter; } // 委托所有默认方法给内部XmlWriter public override void Close() => _innerWriter.Close(); 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 WriteEndAttribute() => _innerWriter.WriteEndAttribute(); public override void WriteEndDocument() => _innerWriter.WriteEndDocument(); 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 WriteState WriteState => _innerWriter.WriteState; public override void WriteString(string text) => _innerWriter.WriteString(text); public override void WriteSurrogateCharEntity(char lowChar, char highChar) => _innerWriter.WriteSurrogateCharEntity(lowChar, highChar); public override void WriteWhitespace(string ws) => _innerWriter.WriteWhitespace(ws); // 重写WriteStartElement,标记当前是否为自闭合元素 public override void WriteStartElement(string prefix, string localName, string ns) { _isSelfClosingElement = true; _innerWriter.WriteStartElement(prefix, localName, ns); } // 写入内容时,说明元素不是自闭合的 public override void WriteElementString(string localName, string value) { _isSelfClosingElement = false; _innerWriter.WriteElementString(localName, value); } // 重写WriteEndElement,处理自闭合标签的输出 public override void WriteEndElement() { if (_isSelfClosingElement) { // 直接写入不带空格的自闭合结尾 _innerWriter.WriteRaw("/>"); } else { _innerWriter.WriteEndElement(); } _isSelfClosingElement = false; } }
使用自定义XmlWriter的代码:
var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = false, NewLineOnAttributes = false }; using (var fileStream = new FileStream(path, FileMode.Create)) using (var xmlWriter = XmlWriter.Create(fileStream, settings)) using (var customWriter = new NoTrailingSpaceXmlWriter(xmlWriter)) { xdoc.Save(customWriter); }
内容的提问来源于stack exchange,提问作者igoose87
相关产品推荐
相关产品推荐

