DelphiLearner
DelphiLearner

Reputation: 489

How to remove name space from XML using Delphi 7

i am using below code to remove name space attribute from xml but i didn;t succeeded. i want to remove Namespace only from nodes Action__CompIntfc__CIName

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

Below is my code

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;

After deleting namespace "xmlns="http://schemas.xmlsoap.org/soap/encoding/" from XML from below node

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

i am expecting my xml to be

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

Upvotes: 2

Views: 2386

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167571

As an alternative to the DOM programming, here is an XSLT 1.0 stylesheet that should do the job:

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

It transforms

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

into

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

as shown in http://xsltransform.net/94rmq6V/1.

As for using it with MSXML, you can use transformNodeToObject, https://msdn.microsoft.com/en-us/library/ms766561%28v=vs.85%29.aspx, together with your input document, a second document into which you load above stylesheet and a result document, as in

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

and create them:

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

load the xmldoc as you do, load the above XSLT code (either from a file using the load method or from a string with loadXML, as you do for the xmldoc), and then call

xmldoc.transformNodeToObject(sheet, result);

Upvotes: 2

MartynA
MartynA

Reputation: 30715

The following works for me.

As you'll see, it works by iterating your RecNodeList looking for nodes with the right name. When it finds one, it creates a new node with the same tagName and text properties, copies its attributes except the 'xmlns' one and then replaces the existing node with the new one.

It also copies the node's first level child nodes and their attributes. If you wanted to copy those child nodes' children (if any) too, it would probably be easiest to write a recursive function to do it, but that doesn't arise with the Xml in your q.

Of course, the method shown is sensitive to the structure of the Xml document and so is rather fragile. I haven't attempted to find out, but I imagine that the XSLT solution suggested in a comment might be equally fragile.

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;

Upvotes: 1

Related Questions