Kirk Evans Blog

.NET From a Markup Perspective

Removing Namespaces in XML, Security in ASP.NET

Removing Namespaces in XML, Security in ASP.NET

Rate This
  • Comments 14

An Update - 05/19/2004

Instead of looking at XSLT for removing namespaces, consider using a specialized System.Xml.XmlTextWriter to remove XML Namespaces.

-ed.

ASP.NET Security

The Patterns and Practices Group introduced "Improving Web Application Security: Threats and Countermeasures", a free PDF download that weighs in at about 6 megs of great information on developing secure web applications.  I haven't read "Building Secure ASP.NET Applications" yet, but this guide is certainly a compelling reason to think about ordering it soon.

Removing Namespaces in XML

I have seen this question and related questions in many newsgroup posts: "How do I remove namespaces from my XML?"  There are several ways to do this.  Of course, I have to demo the XSLT version first. 

<xsl:stylesheet xmlns:xsl ="http://www.w3.org/1999/XSL/Transform" version ="1.0" >
<xsl:template match ="@*" >
<xsl:attribute name ="{local-name()}" >
<xsl:value-of select ="." />
</xsl:attribute>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match ="*" >
<xsl:element name ="{local-name()}" >
<xsl:apply-templates select ="@* | node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Apply this stylesheet to the following XML:

<k:foo xmlns:k ="testing" >
<k:bar id ="1" />
</k:foo>

The result of the transformation will be:

<foo>
<bar id ="1" />
</foo>

This stylesheet basically removes the namespace from the element or attribute. To transform the XML, you have to use the System.Xml.Xsl.XslTransform class. Typically this is done by providing a URL to the file, which internally creates an XPathDocument based on the contents of the file found at the URL.  If you are processing a large XML document in this manner, performance will be horrible:  the transformation process requires that the entire document be loaded into memory. 

Instead of loading the entire document into memory, you can use an XmlTextReader to read the contents of the XML file at the specified URL.  As you read nodes from the XmlTextReader, you write the correct node type to the XmlTextWriter, omitting parameters for namespaces and prefixes.

Response.ContentType = "text/xml";
//Read the original XML file with a pull-model processor
XmlTextReader reader = new System.Xml.XmlTextReader(Server.MapPath("test.xml"));

XmlTextWriter writer = new
  System.Xml.XmlTextWriter(Response.OutputStream,System.Text.Encoding.UTF8);

writer.WriteStartDocument();

while(reader.Read())
{
  switch(reader.NodeType)
  {
    case XmlNodeType.Element:
      writer.WriteStartElement(reader.Name);
      
      if(reader.HasAttributes)
      {            
        //Cannot just use writer.WriteAttributes,
        // else it will also emit xmlns attribute              
        while(reader.MoveToNextAttribute())
        {
          if(reader.Name.CompareTo("xmlns") != 0)
            writer.WriteAttributeString(reader.Name,reader.Value);
        }
        reader.MoveToElement();              
      }
      if(reader.IsEmptyElement)
      {
        writer.WriteEndElement();
      }
      break;
    case XmlNodeType.Text:
      writer.WriteString(reader.Value);
      break;
    case XmlNodeType.CDATA:
      writer.WriteCData(reader.Value);
      break;
    case XmlNodeType.ProcessingInstruction:
      writer.WriteProcessingInstruction(reader.Name,reader.Value);
      break;
    case XmlNodeType.Comment:
      writer.WriteComment(reader.Value);
      break;      
    case XmlNodeType.EntityReference:
      writer.WriteEntityRef(reader.Name);
      break;
    case XmlNodeType.EndElement:
      writer.WriteEndElement();
      break;
  }
}
writer.WriteEndDocument();
writer.Flush();
writer.Close();
reader.Close();

This seems like a lot of work just to remove namespaces, and it is. I previously had done this same task simply by setting the Namespaces property of the XmlTextReader to false (see my post in the the microsoft.public.dotnet.xml newsgroup for a sample).  However, I cannot seem to get this to work with version 1.1 of the framework currently, but I suspect my machine may be doing something odd.

  • Thanks for the code Kirk.

    However, I am trying to think of a scenario or good reason for removing namespaces in an XML document.
  • can I use the same XSLT transformation in VB?If so please give me an example.I'm trying to remove namespaces from a single node.

    thanks,

    mahesh.
  • mahesh.srinivasan@wonderlic.com
  • See the documentation for the System.Xml.Xsl.XslTransform class, namely the Transform() method.
  • As a follow-up, the .Namespaces=false trick I mentioned was taking advantage of a bug in a beta implementation. The .Namespaces property simply specifies whether the document is intended to support only XML 1.0, or XML 1.0 as well as XML Namespaces 1.0.
  • An update...

    Instead of using XSLT for this task, also consider using a specialized System.Xml.XmlTextWriter.

    http://blogs.msdn.com/kaevans/archive/2004/05/16/132959.aspx
  • As for "why remove namespaces from an XML document", the question comes up fairly frequently in newsgroups. The typical use case is that developers are not aware of namespaces, let alone how to query a document that includes namespaces using XPath or XSLT. The novice solution to this problem is typically "remove the namespaces", which may actually be an OK solution in some aspects.
  • The XmlNoNamespaceWriter mentioned here does not work if you are using the XmlTextWriter to serialize an object.
  • It seems that I had a blog fart and left a few bugs in there. Updated version of XmlNoNamespaceWriter at http://blogs.msdn.com/kaevans/archive/2004/08/02/206432.aspx
  • Richard Hallgren recently blogged about how to remove Xml namespaces from Xml documents , as has Kirk

  • Richard Hallgren recently blogged about how to remove Xml namespaces from Xml documents , as has Kirk

Page 1 of 1 (14 items)
Leave a Comment
  • Please add 4 and 6 and type the answer here:
  • Post
Translate This Page
Search
Archive
Archives