【问题标题】:How to remove name space from XML using Delphi 7如何使用 Delphi 7 从 XML 中删除名称空间
【发布时间】:2016-03-07 15:52:22
【问题描述】:

我正在使用下面的代码从 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;

从下面的节点从 XML 中删除命名空间 "xmlns="http://schemas.xmlsoap.org/soap/encoding/" 后

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

【问题讨论】:

  • 那么你的问题是什么?你实际得到了什么结果?
  • 你不能改变DOM树中节点的命名空间,你需要在没有命名空间的不同命名空间中分别创建新的节点。例如,XSLT 可以做到这一点,看起来您的 Delphi 代码使用支持 XSLT 的 MSXML,所以请告诉我们您是否可以使用 XSLT 解决方案。
  • @MartinHonnen:“您无法更改节点的命名空间”确实如此。在我的回答中,我已按照您的建议将有问题的节点替换为新创建的节点,但没有使用 XSLT。

标签: xml delphi namespaces delphi-7


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    以下对我有用。

    正如您将看到的,它通过迭代您的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;
    

    【讨论】:

    • 您需要编写一个递归函数或过程来以同样的方式处理子节点,不是吗?这就是 XSLT 擅长的地方,您可以在命名空间中编写一个匹配元素的模板,并以相同的方式轻松处理内容。
    • 子节点 缺少来自 1 的上述代码。
    • 所以我得到的输出是 1..... 你能改变你的代码吗?
    猜你喜欢
    • 2011-07-13
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    • 2010-11-17
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多