去除结束元素的空格?

3

目前,我正在使用XML来存储许多数据,当创建这些XML文件时,我希望将其大小减小到最小。

我该如何覆盖XmlWriter函数(WriteEndElement),以便不保存它,而是像这样保存:

<thisElement someAttribute="blabla" />

它将被保存为:
<thisElement someAttribute="blabla"/>   

更新:

我正在尝试通过使用以下方法来完成这个任务:

public override void WriteEndElement()

但是我不知道如何修改当前的WriteEndElement函数,也不确定是否有可能进行修改。


标准压缩不起作用吗?如果是这样,我会想出一个答案。 - user47589
将使用xml的应用程序不是由我们制作的,我们已经请求对其进行更改,但它不会很快更改,因此我们正在尽力将其最小化:(其中之一就是更改该空间,有数百万条目的文件。文件大小为200mb、300mb或更多,但这是当前的平均值。 - Guapo
我知道这是一个完全的hack想法,但你可以使用字符串替换。将整个文件放入一个字符串strXML中。在其上运行strXML.Replace("\" />", "\"/>")。然后使用XElement.Parse(strXML) - jb.
@jb 我目前做的事情类似,但我正在寻找一种解决方案,使我能够在生成文件时更改它,因为这对我来说是最好的,因为我只需要做一次,所以我正在寻找一种通过更改WriteEndElement来实现这一点的方法 :) - Guapo
1个回答

1

恐怕没有重写大量代码是不可能的。空格是硬编码在内部类中的,无法配置。

例如,内部XmlEncodedRawTextWriter.WriteEndElement()方法的代码片段。

internal override void WriteEndElement(string prefix, string localName, string ns)
{
    // snip...
    else
    {
        this.bufPos--;
        this.bufChars[this.bufPos++] = ' '; // the space is hard coded
        this.bufChars[this.bufPos++] = '/';
        this.bufChars[this.bufPos++] = '>';
    }
}

我能想到的一些选项是解析输出的XML以搜索关闭标签以手动删除空格,实现自己的XML编写器,使其不包括此空格,或编写一个包装类来使用反射在写入结束元素时修改内部缓冲区。


这里有一个扩展方法可以做到这一点。但请注意,这不是可移植的。虽然它似乎适用于简单的情况,但不能保证适用于所有情况。我认为这里所做的操作不会破坏写入器的状态,但使用时需自行承担风险

public static class XmlWriterExtensions
{
    private static readonly Func<XmlWriter, object> get_writer;
    private static readonly Func<object, char[]> get_bufChars;
    private static readonly Func<object, int> get_bufPos;
    private static readonly Action<object, int> set_bufPos;

    static XmlWriterExtensions()
    {
        var asm = Assembly.GetAssembly(typeof(XmlWriter));
        var xmlWellFormedWriterType = asm.GetType("System.Xml.XmlWellFormedWriter");
        var flags = BindingFlags.NonPublic | BindingFlags.Instance;
        var writerField = xmlWellFormedWriterType.GetField("writer", flags);
        get_writer = w => writerField.GetValue(w);
        var xmlEncodedRawTextWriterType = asm.GetType("System.Xml.XmlEncodedRawTextWriter");
        var bufCharsField = xmlEncodedRawTextWriterType.GetField("bufChars", flags);
        var bufPosField = xmlEncodedRawTextWriterType.GetField("bufPos", flags);
        get_bufChars = w => (char[])bufCharsField.GetValue(w);
        get_bufPos = w => (int)bufPosField.GetValue(w);
        set_bufPos = (w, i) => bufPosField.SetValue(w, i);

    }

    public static void TrimElementEnd(this XmlWriter writer)
    {
        var internalWriter = get_writer(writer);
        char[] bufChars = get_bufChars(internalWriter);
        int bufPos = get_bufPos(internalWriter);
        if (bufPos > 3 && bufChars[bufPos - 3] == ' ' && bufChars[bufPos - 2] == '/' && bufChars[bufPos - 1] == '>')
        {
            bufChars[bufPos - 3] = '/';
            bufChars[bufPos - 2] = '>';
            bufPos--;
            set_bufPos(internalWriter, bufPos);
        }
    }
}

// usage:
Console.OutputEncoding = Encoding.UTF8;
using (var writer = XmlWriter.Create(Console.Out))
{
    writer.WriteStartElement("Foo");
    writer.WriteElementString("Bar", null);
    writer.TrimElementEnd();
    writer.WriteElementString("Baz", null);
    writer.WriteEndElement();
}

 

<?xml version="1.0" encoding="utf-8"?><Foo><Bar/><Baz /></Foo>

这是我目前正在做的事情:“解析输出的XML以搜索结束标记以删除空格”。 - Guapo
@Guapo:请继续关注,我会尝试编写最后一个选项。虽然有些hackish,但是还是可以实现的。 - Jeff Mercado
@Jeff 我期待着它的实现,如果能够实现将是一件幸事。 - Guapo
@Guapo:更新它,将其作为扩展方法。只要您通过调用WriteEndElement()自己结束元素,这应该足够好。 - Jeff Mercado
问题不在于源代码不是公开的...而是实现类似Mono这样的东西时,你不被允许从Microsoft复制代码。它是根据只读许可证发布的,因此创建Mono时,您必须从头编写代码以重新创建相同的行为。引用总的来说,在实现自由软件并且可以访问专有代码时要小心。我们需要确保我们不会意外地使用他人的受版权保护的代码。 - Pauli Østerø
显示剩余2条评论

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