2016-08-22 11 views
0

Я пытаюсь создать следующий XML с помощью кода:Создать фрагмент XML без XMLNS пространства имен декларации

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

Но я не удается избавиться от xmlns:log4j="http://my-project.org/log4j/" добавил. На данный момент я тестирую следующий код (см HERE):

XNamespace ns = "http://my-project.org/log4j/"; 
var root = new XElement("root", new XAttribute(XNamespace.Xmlns + "log4j", ns)); 
var eventElement = new XElement(ns + "event"); 
root.Add(eventElement); 

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

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

Когда я конвертировать eventElement в строку я получаю пространство имен добавляется в log4j:event узел и при преобразовании root он добавляется только корневой элемент (как это должен быть IMO для действительного XML), но как получить узел события только БЕЗ объявления пространства имен только как XML-фрагмент/узел? Я также пробовал использовать XmlWriter, но там же результат.
Я открыт для других аплоасов.

В настоящее время я использую String.Replace(" xmlns:log4j=\"" + ns + "\"", string.Empty), чтобы избавиться от него, но это довольно медленно (сделать полный метод на 50% медленнее), и поскольку это может произойти на высокой частоте (= регистратор), я хотел бы сделать это как можно быстрее.
Причина, по которой я нуждаюсь в этом без объявления пространства имен, заключается в том, что некоторым слушателям журналов не нравится пространство имен и сбою, если они есть (журнал отправляется через UDP для прослушивания журналов).

То, что я пытаюсь улучшить следующая NLog рендерер:
https://github.com/NLog/NLog/blob/master/src/NLog/LayoutRenderers/Log4JXmlEventLayoutRenderer.cs
Помимо медленного Replace (см Ln 300) Я также заменил callsite/UserStackFrame использовать [CallerMemberName] параметры и такие осуществляется мой собственный журнал обертка. Я мог бы ускорить создание журнала из журналов> 100 мс/1к в моей тестовой системе до ~ 35 мс/1к, просто оставив там пространство имен (как и должно быть для корректного XML), но, как уже было сказано, некоторые прослушиватели журналов (например, Sentinel) авария, когда она есть ...

+1

Что вы пытаетесь получить, это 'notXml'. Вы не должны ожидать, что инструменты, которые работают с XML, генерируют что-то другое, что не соответствует требованиям. Если у вас есть инструменты, которые не могут правильно работать с хорошо сформированным XML, вы должны посмотреть на их исправление. Префиксы пространства имен, * сами по себе * не содержат семантического значения. Вы получаете только правильную семантику, когда префикс пространства имен связан с объявлением пространства имен. –

+0

@Damien_The_Unbeliever: Я знаю, что его недействительный XML «сам по себе», поэтому я назвал его «фрагментом XML». Факт в том, что я не могу ни изменить структуру XML, ни инструменты, используемые для их прослушивания, поскольку оба из моих рук и поэтому я стараюсь, чтобы они работали вместе как можно быстрее ... – ChrFin

+0

У вас есть круглые скобки в неправильное место. Вы добавляете «ns» к атрибуту вместо Element: новый XElement («root», новый XAttribute (XNamespace.Xmlns + "log4j"), ns); – jdweng

ответ

1

Выбранный фрагмент хорошо сформирован в мире XML без пространств имен, если вам действительно нужно создать такой фрагмент с .NET, то унаследованное XmlTextWriter позволяет это следующим образом:

 using (StringWriter sw = new StringWriter()) 
     { 

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

Результат:

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

Следует помнить, однако, что большинство XML-парсеров и API-интерфейсов ожидают, что XML-пространство имен будет содержать XML-форму, где имя с двоеточием разрешено только в том случае, если префикс до того, как двоеточие привязано к пространству имен), поэтому созданный фрагмент не может быть обработан с помощью LINQ to XML, например, или XmlReader по умолчанию, созданный с помощью XmlReader.Create.

+0

Спасибо, это было именно то, что мне было нужно - и даже немного быстрее, чем два других подхода (теперь ~ 30 мс/1к журналов). – ChrFin