Как заставить LinqTo XML записывать значение XAtribute как «&» вместо «&»? - PullRequest
0 голосов
/ 09 июля 2020
• 1000 Я знаю, почему фреймворк это делает, он просто соответствует правильному стандарту xml. Однако система, которая будет читать мой результирующий файл xml, не заботится о стандарте XML, она просто использует синтаксис, подобный XML, но сломается, если найдет строку «&» вместо «&» , поэтому, пожалуйста, не читайте мне лекций о стандарте xml. Мне нужно заставить LinqTo Xml создать файл, в котором «&» не заменено на «&». Я знаю, что могу просто взять полученный файл и изменить его с помощью Regex, но в моем коде это выглядело бы беспорядочно, я буду использовать его только в качестве последнего ресурса. Я уже пробовал использовать Unicode вместо "&", это не сработало ...

Код ниже:

snSettingNode.SetAttributeValue("MyValue", "&PlusSomeMoreCharacters");

myXmlNode.Add(new XElement("SomeName", new XAttribute("Value", &PlusSomeMoreCharacters)));

1 Ответ

0 голосов
/ 10 июля 2020

К сожалению. Net написан не для упрощения этой задачи. Один из подходов - создать оболочку для XmlWriter, которая позволяет вам записывать необработанные значения атрибутов.

public class XmlRawAttribWriter : XmlWriter, IDisposable {
    XmlWriter baseWriter;
    bool disposedValue;
    HashSet<string> RawAttributeNames;
    bool LastAttributeIsRaw = false;

    public XmlRawAttribWriter(XmlWriter b) => baseWriter = b;
    public XmlRawAttribWriter(TextWriter output, XmlWriterSettings settings, string[] rawAttributeNames) {
        RawAttributeNames = rawAttributeNames.ToHashSet();
        baseWriter = XmlWriter.Create(output, settings);
    }

    public static XmlRawAttribWriter Create(TextWriter output, XmlWriterSettings settings, params string[] rawAttributeNames) => new XmlRawAttribWriter(output, settings, rawAttributeNames);

    public override WriteState WriteState => baseWriter.WriteState;
    public override void Flush() => baseWriter.Flush();
    public override string LookupPrefix(string ns) => baseWriter.LookupPrefix(ns);
    public override void WriteBase64(byte[] buffer, int index, int count) => baseWriter.WriteBase64(buffer, index, count);
    public override void WriteCData(string text) => baseWriter.WriteCData(text);
    public override void WriteCharEntity(char ch) => baseWriter.WriteCharEntity(ch);
    public override void WriteChars(char[] buffer, int index, int count) => baseWriter.WriteChars(buffer, index, count);
    public override void WriteComment(string text) => baseWriter.WriteComment(text);
    public override void WriteDocType(string name, string pubid, string sysid, string subset) => baseWriter.WriteDocType(name, pubid, sysid, subset);
    public override void WriteEndAttribute() {
        LastAttributeIsRaw = false;
        baseWriter.WriteEndAttribute();
    }
    public override void WriteEndDocument() => baseWriter.WriteEndDocument();
    public override void WriteEndElement() => baseWriter.WriteEndElement();
    public override void WriteEntityRef(string name) => baseWriter.WriteEntityRef(name);
    public override void WriteFullEndElement() => baseWriter.WriteFullEndElement();
    public override void WriteProcessingInstruction(string name, string text) => baseWriter.WriteProcessingInstruction(name, text);
    public override void WriteRaw(char[] buffer, int index, int count) => baseWriter.WriteRaw(buffer, index, count);
    public override void WriteRaw(string data) => baseWriter.WriteRaw(data);
    public override void WriteStartAttribute(string prefix, string localName, string ns) {
        LastAttributeIsRaw = RawAttributeNames.Contains(localName);
        baseWriter.WriteStartAttribute(prefix, localName, ns);
    }
    public override void WriteStartDocument() => baseWriter.WriteStartDocument();
    public override void WriteStartDocument(bool standalone) => baseWriter.WriteStartDocument(standalone);
    public override void WriteStartElement(string prefix, string localName, string ns) => baseWriter.WriteStartElement(prefix, localName, ns);
    public override void WriteString(string text) {
        if (LastAttributeIsRaw)
            baseWriter.WriteRaw(text);
        else
            baseWriter.WriteString(text);
    }
    public override void WriteSurrogateCharEntity(char lowChar, char highChar) => baseWriter.WriteSurrogateCharEntity(lowChar, highChar);
    public override void WriteWhitespace(string ws) => baseWriter.WriteWhitespace(ws);

    protected override void Dispose(bool disposing) {
        if (!disposedValue) {
            if (disposing) {
                baseWriter.Dispose();
            }

            disposedValue = true;
        }
    }
}

Вы можете использовать XmlRawAttribWriter вместо XmlWriter - вот несколько примеров использования:

public static class LinqXmlExt {
    public static string GetRawAttribXmlString(this XNode x, params string[] rawAttributeNames) {
        using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) {
            var ws = new XmlWriterSettings();
            ws.OmitXmlDeclaration = true;
            ws.Indent = true;
            if (x is XText)
                ws.ConformanceLevel = ConformanceLevel.Fragment;
            var sw2 = new StringWriter(CultureInfo.InvariantCulture);
            var ws2 = new XmlWriterSettings();
            using (var w = XmlRawAttribWriter.Create(sw, ws, rawAttributeNames)) {
                x.WriteTo(w);
            }
            return sw.ToString();
        }
    }

    public static string ToRawAttribString(this XNode x, params string[] rawAttributeNames) => x.GetRawAttribXmlString(rawAttributeNames);
}

С его помощью вы можете получить строку XML для XDocument, имеющего необработанное значение атрибута:

var xmlString = xml.ToRawAttribString("MyValue");

При необходимости вы можете изменить XmlRawAttribWriter для отслеживания текущего элемента, сохраняя localName в методе WriteStartElement, чтобы влиять только на атрибуты определенных элементов, передавая что-то вроде «element: attribute» для сопоставления.

Если вы используете другие методы (например, XDocument.Save), вы можете создать соответствующие методы расширения (например, SaveRaw), которые принимают имена атрибутов, чтобы их значения выводились как необработанные.

...