You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 09:47:02