ChrFin ChrFin - 1 year ago 116
C# Question

Create XML fragment without xmlns namespace declaration

I am trying to create the following XML via code:

<log4j:event logger="MyTools" level="WARN" timestamp="763">
<log4j:message>This is a log message.</log4j:message>

But I do not manage to get rid of the
added. At the moment I am testing the following code (see HERE):

XNamespace ns = "";
var root = new XElement("root", new XAttribute(XNamespace.Xmlns + "log4j", ns));
var eventElement = new XElement(ns + "event");

eventElement.SetAttributeValue("logger", "MyTools");
eventElement.SetAttributeValue("level", "WARN");
eventElement.SetAttributeValue("timestamp", DateTime.Now.Millisecond);

eventElement.SetElementValue(ns + "message", "This is a log message.");

When I convert
to string I get the namespace added to the
node and when converting
it is added to the root element only (as it should be IMO for valid XML), but how to get the event node only WITHOUT the namespace declaration as an XML fragment/node only?
I have also tried using XmlWriter but same result there.

I am open for other aproaches also.

At the moment I use
String.Replace(" xmlns:log4j=\"" + ns + "\"", string.Empty)
to get rid of it, but that is rather slow (making the complete method ~50% slower) and as this can happen at a high frequency (=logger) I would like to make it as fast as possible.

The reason I need it without the namespace declaration is that some log listeners do not like the namespace and crash if it is there (log is sent via UDP to log listeners).

What I am trying to improve is the following NLog renderer:

Aside from the slow
(see Ln 300) I also replaced the callsite /
to use the
parameters and such implemented by my own log wrapper. I could speed up the log generation from >100ms/1k logs on my test system to ~35ms/1k when just leaving the namespace in there (as it should be for valid XML), but as already said some log listeners (i.e. Sentinel) crash when it is there...

Answer Source

The snippet you have shown is well-formed in the world of XML without namespaces, if you really need to create such a snippet with .NET then a legacy XmlTextWriter allows that as follows:

        using (StringWriter sw = new StringWriter())

            using (XmlTextWriter xtw = new XmlTextWriter(sw))
                xtw.Namespaces = false;
                xtw.Formatting = Formatting.Indented;
                xtw.WriteAttributeString("logger", "MyTools");
                xtw.WriteAttributeString("level", "WARN");
                xtw.WriteAttributeString("timestamp", "763");
                xtw.WriteElementString("log4j:message", "This is a log message.");
            string result = sw.ToString();


<log4j:event logger="MyTools" level="WARN" timestamp="763">
  <log4j:message>This is a log message.</log4j:message>

Be warned however that nowadays most XML parsers and APIs expect namespace well-formed XML (where a name with a colon is only allowed if the prefix before the colon is bound to a namespace) so the created snippet could not be processed with LINQ to XML for instance or the default XmlReader created with XmlReader.Create.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download