2

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>
3
  • So what is your question? What result do you actually get? Commented Mar 7, 2016 at 16:27
  • You can't change the namespace of a node in a DOM tree, you would need to create new nodes in a different namespace respectively in no namespace. XSLT can do that for instance, it looks like your Delphi code uses MSXML which support XSLT, so tell us whether you could use an XSLT solution. Commented Mar 7, 2016 at 16:52
  • @MartinHonnen: "You can't change the namespace of a node" Indeed. In my answer, I've replaced the nodes in question with newly-created ones, as you suggested, but without resorting to XSLT. Commented Mar 7, 2016 at 19:31

2 Answers 2

2

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);
Sign up to request clarification or add additional context in comments.

Comments

1

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;

3 Comments

You would need to write a recursive function or procedure to treat the child nodes the same way, no? That is where XSLT excels, you would write one template matching elements in the namespace and easily process the contents the same way.
Child node <test >is missing with above code from <Action__CompIntfc__CIName> <test>1</test> </Action__CompIntfc__CIName>.
so i am getting output as <Action__CompIntfc__CIName>1</Action__CompIntfc__CIName>..... Can you please change your code?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.