Changing XML node attribute value gives “Namespace error”

不问归期 提交于 2019-12-10 18:50:26

问题


I use TXMLDocument to create XML documents. Sometimes I need to change attribute values. I get a "Namespace error" if I use the "ADOM XML v4" DOM vendor (Delphi XE2).

Example code:

procedure TForm1.Button1Click(Sender: TObject);
var
  XML: TXMLDocument;
  XMLNode, XMLSubNode: IXMLNode;
begin
  XML := TXMLDocument.Create(nil);
  //XML.DOMVendor := GetDOMVendor('MSXML'); // Works using MSXML
  XML.DOMVendor := GetDOMVendor('ADOM XML v4');
  XML.Active := True;
  XMLNode := XML.AddChild('test');
  XMLNode.Attributes['state'] := 1;
  XMLNode.Attributes['state'] := 0; // Raises "Namespace error"
end;

If I use MSXML, then everything works fine. I want to use ADOM XML because I'm generating large XML files and it seems to be a lot faster than MSXML.

How do I change the attribute value?


回答1:


This is a bug. A pretty major one too. With the current implementation of the ADOM XML vendor, if you create an attribute in the null namespace, you cannot change its value.

Here is the offending code from the AdomCore_4_3 unit, as bundled with Delphi 2010.

procedure TDomAttr.SetPrefix(const Value: WideString);
begin
  if IsReadonly then
    raise ENo_Modification_Allowed_Err.Create('No modification allowed error.');

  if NodeName = 'xmlns' then
    raise ENamespace_Err.Create('Namespace error.');

  if NamespaceURI = 'http://www.w3.org/2000/xmlns/' then begin
    if Value <> 'xmlns' then
      raise ENamespace_Err.Create('Namespace error.');
  end else if NamespaceURI = 'http://www.w3.org/XML/1998/namespace' then begin
    if Value <> 'xml' then
      raise ENamespace_Err.Create('Namespace error.');
  end else begin
    if NamespaceURI = '' then
      raise ENamespace_Err.Create('Namespace error.');
    if Value = 'xml' then
      raise ENamespace_Err.Create('Namespace error.');
    if Value = 'xmlns' then
      raise ENamespace_Err.Create('Namespace error.');
  end;

  if Value = '' then begin
    if (NamespaceURI = 'http://www.w3.org/2000/xmlns/') then
      raise ENamespace_Err.Create('Namespace error.');
    FPrefix := '';
    FNodeName := LocalName;
    Exit;
  end;

  if not IsXmlName(Value) then
    raise EInvalid_Character_Err.Create('Invalid character error.');
  if not IsXmlPrefix(Value) then
    raise ENamespace_Err.Create('Namespace error.');

  FPrefix := Value;
  FNodeName := Concat(Value, ':', LocalName);
end;

In the above, the issue can be isolated to here...

    if NamespaceURI = '' then
      raise ENamespace_Err.Create('Namespace error.');

Work-around 1

I have no idea what the author's intent was, but as it stands, this test is nonsense. To fix, remove this test and recompile.

Work-around 2

As an alternative, you could delete the attribute before setting like this ...

procedure TForm6.Button1Click(Sender: TObject);
var
  XML: TXMLDocument;
  XMLNode, XMLSubNode: IXMLNode;
  OldAttrib: IXMLNode;
begin
  XML := TXMLDocument.Create(nil);
  //XML.DOMVendor := GetDOMVendor('MSXML'); // Works using MSXML
  XML.DOMVendor := GetDOMVendor('ADOM XML v4');
  XML.Active := True;
  XMLNode := XML.AddChild('test');
  XMLNode.Attributes['state'] := 1;
  OldAttrib := XMLNode.AttributeNodes.FindNode('state');
  if assigned( OldAttrib) then
    XMLNode.AttributeNodes.Remove( OldAttrib);
  XMLNode.Attributes['state'] := 0; 
end;


来源:https://stackoverflow.com/questions/11794540/changing-xml-node-attribute-value-gives-namespace-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!