Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XDocument or XElement parsing of XML element containing namespaces

I am try to read the following string, captured from a log4net UdpAppender.

<log4net:event logger="TestingTransmitter.Program" 
               timestamp="2009-08-02T17:50:18.928+01:00" 
               level="ERROR" 
               thread="9" 
               domain="TestingTransmitter.vshost.exe" 
               username="domain\user">
    <log4net:message>Log entry 103</log4net:message>
    <log4net:properties>
        <log4net:data name="log4net:HostName" value="machine" />
    </log4net:properties>
</log4net:event>

When trying to XElement.Parse or XDocument.Parse the content, it throws an exception:

'log4net' is an undeclared namespace. Line 1, position 2.

I know I can search and replace "log4net:" in the original string and remove it, allowing me to parse the XML successfully, but is there a better way? This is the complete data captured (reformatted to allow reading), there are no xml namespace declarations made or removed..

like image 800
Ray Hayes Avatar asked Aug 02 '09 18:08

Ray Hayes


People also ask

What is XElement C#?

The XElement class is one of the fundamental classes in LINQ to XML. It represents an XML element. The following list shows what you can use this class for: Create elements. Change the content of the element.

How do you declare XElement in C#?

XElement element = XElement. Load(var); c#


2 Answers

First, create an instance of XmlNamespaceManager class, and add your namespaces to that, e.g.

    XmlNamespaceManager mngr = new XmlNamespaceManager( new NameTable() );
    mngr.AddNamespace( "xsi", "http://www.w3.org/2001/XMLSchema-instance" );
    mngr.AddNamespace( "xsd", "http://www.w3.org/2001/XMLSchema" );

To parse an XML string using those namespace mappings, call the following function, passing the instance of XmlNamespaceManager with the namespaces you've added to it:

/// <summary>Same as XElement.Parse(), but supports XML namespaces.</summary>
/// <param name="strXml">A String that contains XML.</param>
/// <param name="mngr">The XmlNamespaceManager to use for looking up namespace information.</param>
/// <returns>An XElement populated from the string that contains XML.</returns>
public static XElement ParseElement( string strXml, XmlNamespaceManager mngr )
{
    XmlParserContext parserContext = new XmlParserContext( null, mngr, null, XmlSpace.None );
    XmlTextReader txtReader = new XmlTextReader( strXml, XmlNodeType.Element, parserContext );
    return XElement.Load( txtReader );
}
like image 165
Soonts Avatar answered Nov 09 '22 04:11

Soonts


You really only have two options:

  1. Strip "log4net:" from the XML, as you suggested;
  2. Modify the XML to declare the namespace, probably most easily accomplished by wrapping the fragment (via StringBuilder) in a root element that has the declaration.

Strictly speaking, your example is malformed XML -- it's no surprise XDocument / XElement won't parse it.

like image 36
Ben M Avatar answered Nov 09 '22 06:11

Ben M