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

时间:2016-03-07 15:52:22

标签: xml delphi namespaces delphi-7

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

删除名称空间
<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;

删除命名空间&#34; xmlns =&#34; http://schemas.xmlsoap.org/soap/encoding/"来自节点下面的XML

<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>

2 个答案:

答案 0 :(得分:2)

作为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);

答案 1 :(得分:1)

以下适用于我。

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

它还复制节点的第一级子节点及其属性。如果你想复制那些子节点的子节点(如果有的话),那么编写递归函数可能最容易,但是q中的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;