如何使TXMLDocument(使用MSXML实现)始终包含编码属性?

9

我有一些遗留代码(不是我写的),它总是包括编码属性,但重新编译到D2010时,TXMLDocument不再包括编码。因为XML数据在标签和数据上都有重音字符,所以TXMLDocument.LoadFromFile只是简单地抛出EDOMParseErros错误,表示在文件中找到了无效字符。相关代码:

   Doc := TXMLDocument.Create(nil);  
   try
     Doc.Active := True;
     Doc.Encoding := XMLEncoding;
     RootNode := Doc.CreateElement('Test', '');
     Doc.DocumentElement := RootNode;
     <snip>
     //Result := Doc.XMl.Text;
     Doc.SaveToXML(Result);    // Both lines gives the same result

在旧版本的Delphi中,将生成以下行:
<?xml version="1.0" encoding="ISO-8859-1"?>

在D2010中,会生成如下内容:
<?xml version="1.0"?>

如果我手动更改这一行,所有东西都像过去几年一样正常工作。

更新:XMLEncoding是一个常量,并且定义如下

  XMLEncoding = 'ISO-8859-1';
2个回答

6

您需要查看IXMLDocument.CreateProcessingStruction。我使用OmniXML,但其语法类似,应该能帮助您入门:

var
  FDoc: IXMLDocument;
  PI:  IXMLProcessingInstruction;
begin
  FDoc := OmniXML.CreateXMLDoc();
  PI := FDoc.CreateProcessingInstruction('xml', 'version="1.0" encoding="UTF-8"');
  FDoc.AppendChild(PI);
end;

这正是微软为MSXML推荐的做法:http://msdn.microsoft.com/en-us/library/aa468560.aspx。然而,在文档开头的那个东西在技术上并不是处理指令。它是一个* XML声明 *;字符串“xml”实际上不允许用作处理指令的名称,因此似乎CreateProcessingInstruction方法正在执行双重任务。 - Rob Kennedy
@Rob:这可能就是为什么几年前我花了一段时间才弄明白它(当时没有你提供的MSDN链接)。然而,如果它告诉解析器如何解释内容,它实际上可以被认为是一个处理指令,不是吗?“这是XML,并且它使用这个字符集——这将使它更容易理解。” - Ken White

4
var 
  XMLStream: TStringStream;
begin  
   Doc := TXMLDocument.Create(nil);  
   try
     Doc.Active := True;
     Doc.Encoding := XMLEncoding;
     RootNode := Doc.CreateElement('Test', '');
     Doc.DocumentElement := RootNode;
     <snip>
     XMLStream := TStringStream.Create;
     Doc.SaveToStream(XMLStream);
     Result := XmlStream.DataString;
     XMLStream.Free;

自从看了Ken的回答和链接到MSXML文章后,我决定研究XML属性和SaveToXML方法。两者都使用MSXMLDOM实现中的XML属性 - 在文章中说直接读取时不会带有编码(在CreateProcessInstruction方法之后的“使用MSXML创建新的XML文档”部分)。
更新:
我发现结果XML中的重音字符被截断。当该XML的处理器开始抛出奇怪的错误时,我们发现这些字符被转换为数字字符常量(#13是回车符的数字字符常量)。所以,我使用TStringStream终于解决了这个问题。

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