如何使用Delphi 7从XML中删除名称空间
我正在使用下面的代码从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>
以下适用于我。
正如你所看到的,它通过迭代你的RecNodeList
来寻找名称正确的节点。当找到它时,它将创建一个具有相同tagName
和text
属性的新节点,复制其属性(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的优点,您可以在名称空间中编写一个匹配元素的模板,并以相同的方式轻松处理内容。 –
子节点
所以我得到输出为
作为替代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,您可以与您的输入文档,你加载上面样式表和结果文件到其中的第二个文件,使用transformNodeToObject
,https://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);
那么你的问题是什么?你实际得到了什么结果? – MartynA
您无法更改DOM树中某个节点的名称空间,因此您需要分别在不使用名称空间的情况下在不同名称空间中创建新节点。例如XSLT可以做到这一点,它看起来像你的Delphi代码使用支持XSLT的MSXML,所以告诉我们你是否可以使用XSLT解决方案。 –
@MartinHonnen:“你不能改变节点的名字空间”确实如此。在我的回答中,我已经用新创建的代替了所讨论的节点,正如你所建议的那样,但是不使用XSLT。 – MartynA