2016-03-07 103 views
2

我正在使用下面的代碼從XML刪除名稱空間屬性,但我沒有成功。我只想從節點刪除命名空間Action__CompIntfc__CIName如何使用Delphi 7從XML中刪除名稱空間

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

刪除命名空間 「的xmlns =」 後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> 
+0

那麼你的問題是什麼?你實際得到了什麼結果? – MartynA

+0

您無法更改DOM樹中某個節點的名稱空間,因此您需要分別在不使用名稱空間的情況下在不同名稱空間中創建新節點。例如XSLT可以做到這一點,它看起來像你的Delphi代碼使用支持XSLT的MSXML,所以告訴我們你是否可以使用XSLT解決方案。 –

+0

@MartinHonnen:「你不能改變節點的名字空間」確實如此。在我的回答中,我已經用新創建的代替了所討論的節點,正如你所建議的那樣,但是不使用XSLT。 – MartynA

回答

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; 
+0

您需要編寫一個遞歸函數或過程來以相同的方式處理子節點,否?這就是XSLT的優點,您可以在名稱空間中編寫一個匹配元素的模板,並以相同的方式輕鬆處理內容。 –

+0

子節點缺少上面的代碼 。 – DelphiLearner

+0

所以我得到輸出爲 1 .....你能否改變你的代碼? – DelphiLearner

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> 

,如所示。

至於使用它與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); 
相關問題