Как получить IXmlDomDocument2.XML для правильного экранирования кавычек? - PullRequest
1 голос
/ 04 февраля 2011

Я работаю над проблемой, когда XML, экспортируемый из нашей программы, не экранирует кавычки (превращая " в ",), приводя к проблемам на принимающей стороне. Он отлично выходит за пределы & s и угловых скобок, но не в кавычках.

Когда я копался в коде экспорта XML, я обнаружил, что это довольно простой IXmlDomDocument2 интерфейс DOM. Но когда я добрался до шага, где он производит вывод XML-строки, вызвав метод .XML, я натолкнулся на smack в стене собственности, в которую я не могу проследить, поскольку вся работа выполняется внутри C:\Windows\System32\msxml3.dll .

Так что, очевидно, реализация Microsoft IXmlDomDocument2 знает, как экранировать некоторые символы, но не другие. И, что еще хуже, очевидное, но уродливое решение (выполнение шага предварительной обработки путем рекурсивного обхода всего документа и замены всех кавычек в значениях на «» перед вызовом .XML,) не будет работать, поскольку * Метод увидит эти & s там и избежит их! Есть ли способ исправить это?

1 Ответ

3 голосов
/ 04 февраля 2011

Это можно считать ошибкой в ​​XML-парсере, используемом на другом конце. Спецификация XML детализирует сущности, которые можно экранировать. Но их нужно только экранировать внутри атрибутов, что работает, как показано здесь:

program Project2;

{$APPTYPE CONSOLE}

uses
  ActiveX,
  MSXML2_TLB,
  SysUtils;
var
  Dom : IXMLDOMDocument2;
  Root :  IXMLDOMNode;
  Attr : IXMLDOMNode;
begin
  CoInitialize(nil);
  try
    DOM := CoDOMDocument40.Create;
    Root := Dom.createElement('root');
    Attr := Dom.createAttribute('attr');
    Attr.text := '"';
    root.attributes.setNamedItem(Attr);
    root.text := '"Hello World"';
    DOM.appendChild(Root);
    writeln(Root.xml);
    readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.

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

program Project2;

{$APPTYPE CONSOLE}

uses
  ActiveX,
  MSXML2_TLB,
  SysUtils;
function QuoteEscape(const v : String) : String;
begin
  result := StringReplace(V,'"','"',[rfReplaceAll]);
end;


var
  Dom : IXMLDOMDocument2;
  Root :  IXMLDOMNode;
  Attr : IXMLDOMNode;
begin
  CoInitialize(nil);
  try
    DOM := CoDOMDocument40.Create;
    Root := Dom.createElement('root');
    Attr := Dom.createAttribute('attr');
    Attr.text := '"';
    root.attributes.setNamedItem(Attr);
    root.text :=  QuoteEscape('"Hello World"');
    DOM.appendChild(Root);
    writeln(StringReplace(Root.xml,'"','"',[rfReplaceAll]));
    readln;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
...