Delphi TXmlDocument:意外的属性名称/无法设置xsi:type

时间:2016-12-21 13:12:18

标签: xml delphi xml-parsing

我正在使用带有TXmlDocumentIXmlNode的Delphi 2007将xsi:type属性设置为新的xml节点,但我得到的结果与预期不同。

with fieldNode do
    begin
        Attributes['xmlns:xsi'] := 'http://www.w3.org/2001/XMLSchema-instance';
        Attributes['xmlns:xsd'] := 'http://www.w3.org/2001/XMLSchema';
        Attributes['xsi:type'] := 'FieldImage';
        Attributes['xmlns'] := '';
    end;

我希望输出为:

<SerializableField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="FieldImage" xmlns="">

但相反,我得到了:

<SerializableField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" type="FieldImage" xmlns="">

缺少xsi:部分。这是Delphi中的已知错误还是我做错了什么?

更新

使用下面答案中提供的控制台应用程序,生成的XML与预期的xsi:type属性一致。我无法在我的应用中重新创建它。它是一个delphi.net应用程序,如果这有任何区别?

我已经制作了一个解决方法,即将XML转换为字符串并执行字符串替换,但这似乎没必要,而且有点脏......

2 个答案:

答案 0 :(得分:0)

我在Delphi XE7 / Win10中制作了一个MVCE(你应该提供的):

program SO41263595;

{$APPTYPE CONSOLE}

uses
  XmlIntf,
  XmlDoc,
  ActiveX,
  SysUtils;

procedure Test;

var
  Doc : IXMLDocument;
  Node : IXMLNode;

begin
 Doc := LoadXMLData('<test><node/></test>');
 Node := Doc.DocumentElement.ChildNodes[0];
 Node.Attributes['xmlns:xsi'] := 'http://www.w3.org/2001/XMLSchema-instance';
 Node.Attributes['xmlns:xsd'] := 'http://www.w3.org/2001/XMLSchema';
 Node.Attributes['xsi:type'] := 'FieldImage';
 Node.Attributes['xmlns'] := '';
 Writeln(Doc.XML.Text);
end;

begin
  try
    try
     CoInitialize(nil);
     Test;
    finally
     CoUninitialize;
    end;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

这给出了正确的输出:

<test><node xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="FieldImage" xmlns=""/></test>

如果此MVCE产生与您相同的问题,那么它可能是Delphi错误或MSXML库问题(TXMLDocument是一个包装器)。

答案 1 :(得分:0)

在声明XML命名空间(xmlns属性)时,您应该使用IXMLNode.DeclareNamespace()方法,不要直接使用IXMLNode.Attributes属性。这样做只会创建属性,但不会让DOM知道命名空间实际存在。 DeclareNamespace()将生成必要的xmlns属性,并在DOM中注册名称空间,以便底层XML引擎在创建新节点/属性时可以使用它们。这很重要,这样子节点就可以正确地继承父节点的名称空间。

设置名称空间中的属性时,可以使用Attributes属性,也可以使用IXMLNode.SetAttributeNS()方法。

试试这个:

with fieldNode do
begin
  DeclareNamespace('xsi', 'http://www.w3.org/2001/XMLSchema-instance');
  DeclareNamespace('xsd', 'http://www.w3.org/2001/XMLSchema');
  Attributes['xsi:type'] := 'FieldImage';
  // alternatively:
  // SetAttributeNS('type', 'http://www.w3.org/2001/XMLSchema-instance', 'FieldImage');
  DeclareNamespace('', '');
end;

这会产生预期的XML:

<SerializableField xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="FieldImage" xmlns="">