如何使用 Delphi 从 XML 中删除名称 space 7

How to remove name space from XML using Delphi 7

我正在使用下面的代码从 xml 中删除名称 space 属性,但我没有成功。我只想从节点 Action__CompIntfc__CIName

中删除 Namespace
<Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">

下面是我的代码

procedure TForm1.Button1Click(Sender: TObject);
var
  xmldoc : IXMLDOMDocument;
  xmlString : WideString;
  RecNodelist: IXMLDOMNodeList;
  DataNode: IXMLDOMElement;
  attr :  IXMLDOMAttribute;
begin
  xmlString := '<?xml version="1.0"?>'
  +'<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'
    +'<SOAP-ENV:Body>'
      +'<Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">'
        +'<test>1</test>'
      +'</Action__CompIntfc__CIName>'
      +'<Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">'
        +'<test>15</test>'
      +'</Action__CompIntfc__CIName>'
    +'</SOAP-ENV:Body>'
  +'</SOAP-ENV:Envelope>';
  try
    XMLdoc := CoDOMDocument.Create;
    xmldoc.loadXML(xmlString);
    RecNodelist := XMLdoc.selectNodes('//SOAP-ENV:Envelope/SOAP-ENV:Body/Action__CompIntfc__CIName');
    DataNode := RecNodelist.NextNode as IXMLDOMElement;
    while DataNode <> nil do
    begin
      showmessage(DataNode.xml);
      attr := DataNode.getAttributeNode('xmlns');
      DataNode.removeAttributeNode(attr);
      showmessage(DataNode.xml);
      DataNode := RecNodelist.NextNode as IXMLDOMElement;
    end;
  except
   on e: Exception do
   begin
     ShowMessage(e.Message);
   end;
  end;
end;

删除名称space "xmlns="http://schemas.xmlsoap.org/soap/encoding/" from XML from below node

<Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">

我希望我的 xml 成为

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Body>

    <Action__CompIntfc__CIName>
      <test>1</test>
    </Action__CompIntfc__CIName>

    <Action__CompIntfc__CIName>
      <test>15</test>
    </Action__CompIntfc__CIName>

  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

以下适合我。

如您所见,它通过迭代 RecNodeList 寻找具有正确名称的节点来工作。当它找到一个时,它会创建一个具有相同 tagNametext 属性的新节点,复制其除 'xmlns' 属性之外的属性,然后用新节点替换现有节点。

它还会复制节点的第一级子节点及其属性。如果你也想复制那些子节点的子节点(如果有的话),编写一个递归函数可能是最简单的,但是你的 q.Xml 中的 Xml 不会出现这种情况。

当然,显示的方法对 Xml 文档的结构敏感,因此相当脆弱。我没有尝试找出答案,但我想评论中建议的 XSLT 解决方案可能同样脆弱。

procedure TForm1.RemoveNS;
var
  xmldoc : IXMLDOMDocument;
  xmlString : WideString;
  Target : String;
  RecNodelist: IXMLDOMNodeList;
  DataNode: IXMLDOMElement;
  NextNode : IXMLDOMNode;
  NewNode: IXMLDOMElement;
  AttrNode : IXMLDOmNode;
  ChildNode : IXMLDomElement;
  Map : IXMLDOMNamedNodeMap;
  i,
  j : Integer;
begin

  // remove Namespace only from nodes
  //  <Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">

  xmlString := '<?xml version="1.0"?>'#13#10
  +'<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">'#13#10
    +'<SOAP-ENV:Body>'#13#10
      +'<Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/" anattr="hello">'#13#10
        +'<test attr="123">1</test>'#13#10
      +'</Action__CompIntfc__CIName>'#13#10
      +'<Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">'#13#10
        +'<test>15</test>'#13#10
      +'</Action__CompIntfc__CIName>'#13#10
    +'</SOAP-ENV:Body>'#13#10
  +'</SOAP-ENV:Envelope>'#13#10;

  Memo1.Lines.Text := xmlString;
  Target := 'Action__CompIntfc__CIName';
  xmldoc := CoDOMDocument.Create;

  try
    xmldoc.loadXML(xmlString);
    RecNodelist := xmldoc.selectNodes('//SOAP-ENV:Envelope/SOAP-ENV:Body/Action__CompIntfc__CIName');

    DataNode := RecNodelist.NextNode as IXMLDOMElement;
    while DataNode <> nil do
    begin
      NextNode := DataNode.nextSibling;
      if CompareText(DataNode.nodeName, Target) = 0 then begin
        NewNode := XMLDoc.createElement(DataNode.tagName);
        NewNode.text := DataNode.Text;

        //  copy the existing node's Attributes
        Map := DataNode.attributes;
        for i := 0 to Map.length - 1 do begin
          AttrNode := Map.item[i];
          if CompareText(AttrNode.NodeName, 'xmlns') <> 0 then
            NewNode.SetAttribute(AttrNode.NodeName, AttrNode.NodeValue);
        end;

        //  Create (first level) child nodes matching the existing node's
        //  children and any attributes they have
        for i := 0 to DataNode.childNodes.length - 1 do begin
          ChildNode := XMLDoc.createElement(DataNode.childNodes.item[i].nodeName);
          ChildNode.text := DataNode.childNodes.item[i].Text;

          Map := DataNode.childNodes.item[i].attributes;
          for j:= 0 to Map.length - 1 do begin
            AttrNode := Map.item[j];
            ChildNode.SetAttribute(AttrNode.NodeName, AttrNode.NodeValue);
          end;

          NewNode.appendChild(ChildNode);
        end;
        DataNode.parentNode.replaceChild(NewNode, DataNode);
      end;
      DataNode := NextNode as IXmlDOMElement;
    end;

    Memo2.Lines.Text := XmlDoc.documentElement.xml;
  except
   on e: Exception do
   begin
     ShowMessage(e.Message);
   end;
  end;
   xmldoc := Nil;  // not strictly necessary because it will get finalized when this procedure exits, but anyway
end;

作为 DOM 编程的替代方案,这里有一个 XSLT 1.0 样式表可以完成这项工作:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:se="http://schemas.xmlsoap.org/soap/encoding/" exclude-result-prefixes="se">

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="se:*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

</xsl:transform>

它改变了

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
    <SOAP-ENV:Body>
        <Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">
            <test>1</test>
        </Action__CompIntfc__CIName>
        <Action__CompIntfc__CIName xmlns="http://schemas.xmlsoap.org/soap/encoding/">
            <test>15</test>
        </Action__CompIntfc__CIName>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

进入

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
    <SOAP-ENV:Body>
        <Action__CompIntfc__CIName>
            <test>1</test>
        </Action__CompIntfc__CIName>
        <Action__CompIntfc__CIName>
            <test>15</test>
        </Action__CompIntfc__CIName>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

如图http://xsltransform.net/94rmq6V/1.

至于将它与 MSXML 一起使用,您可以将 transformNodeToObjecthttps://msdn.microsoft.com/en-us/library/ms766561%28v=vs.85%29.aspx 与您的输入文档、您在其中加载样式表和结果文档的第二个文档一起使用,如

var
  xmldoc : IXMLDOMDocument;
  sheet : IXMLDOMDocument;
  result : IXMLDOMDocument;

并创建它们:

xmldoc := CoDOMDocument.Create;
sheet := CoDOMDocument.Create;
result := CoDOMDocument.Create;

像您一样加载 xmldoc,加载上面的 XSLT 代码(使用 load 方法从文件或使用 loadXML 的字符串加载,就像您对 xmldoc 所做的那样),以及然后打电话

xmldoc.transformNodeToObject(sheet, result);