Удаление пространств имен во время сериализации XML

#c# #xml-serialization

#c# #xml-сериализация

Вопрос:

Учитывая этот общий код сериализации:

 public virtual string Serialize(System.Text.Encoding encoding)
{
 System.IO.StreamReader streamReader = null;
 System.IO.MemoryStream memoryStream = null;

 memoryStream = new System.IO.MemoryStream();
 System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
 xmlWriterSettings.Encoding = encoding;
 System.Xml.XmlWriter xmlWriter = XmlWriter.Create(memoryStream, xmlWriterSettings);
 Serializer.Serialize(xmlWriter, this);
 memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
 streamReader = new System.IO.StreamReader(memoryStream);
 return streamReader.ReadToEnd();
}
  

и этот объект (созданный из xsd2code):

 [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.225")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "Com.Foo.Request")]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "Com.Foo.Request", IsNullable = false)]
public partial class REQUEST_GROUP
{

 [EditorBrowsable(EditorBrowsableState.Never)]
 private List<REQUESTING_PARTY> rEQUESTING_PARTYField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private RECEIVING_PARTY rECEIVING_PARTYField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private SUBMITTING_PARTY sUBMITTING_PARTYField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private REQUEST rEQUESTField;

 [EditorBrowsable(EditorBrowsableState.Never)]
 private string iDField;

 public REQUEST_GROUP()
 {
  this.rEQUESTField = new REQUEST();
  this.sUBMITTING_PARTYField = new SUBMITTING_PARTY();
  this.rECEIVING_PARTYField = new RECEIVING_PARTY();
  this.rEQUESTING_PARTYField = new List<REQUESTING_PARTY>();
  this.IDField = "2.1";
 }
}
  

Вывод из сериализации с использованием кода utf-8:

<?xml version="1.0" encoding="utf-8"?>
<REQUEST_GROUP xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="2.1" xmlns="Com.Foo.Request">
<RECEIVING_PARTY />
<SUBMITTING_PARTY />
<REQUEST LoginAccountIdentifier="xxx" LoginAccountPassword="yyy" _RecordIdentifier="" _JobIdentifier="">
<REQUESTDATA>
<PROPERTY_INFORMATION_REQUEST _SpecialInstructionsDescription="" _ActionType="Submit">
<_DATA_PRODUCT _ShortSubjectReport="Y" />
<_PROPERTY_CRITERIA _City="Sunshine City" _StreetAddress2="" _StreetAddress="123 Main Street" _State="CA" _PostalCode="12345">
<PARSED_STREET_ADDRESS />
</_PROPERTY_CRITERIA>
<_SEARCH_CRITERIA />
<_RESPONSE_CRITERIA />
</PROPERTY_INFORMATION_REQUEST>
</REQUESTDATA>
</REQUEST>
</REQUEST_GROUP>

РЕДАКТИРОВАТЬ Вопрос 1: Как мне украсить класс таким образом или манипулировать сериализатором, чтобы избавиться от всех пространств имен в узле REQUEST_GROUP во время обработки, А НЕ после обработки с помощью xslt или regex.

Вопрос 2: Бонусный балл, если бы вы могли также добавить тип doc.

Спасибо.

Ответ №1:

Вы можете удалить пространства имен следующим образом:

 XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
ns.Add(string.Empty, "Com.Foo.Request");
Serializer.Serialize(xmlWriter, this, ns);
  

Что касается добавления doctype, я знаю, что можно создать пользовательский XmlWriter и просто переопределить WriteStartDocument с помощью метода, который вызывает WriteDocType , но я отчасти надеюсь, что кто-то еще знает более простой способ, чем этот.

РЕДАКТИРОВАТЬ: Кстати, я настоятельно рекомендую использовать using :

 using(System.Xml.XmlWriter xmlWriter = XmlWriter.Create(etc.))
{
  // use it here.
}
  

Он автоматически обрабатывает очистку потоков, вызывая Dispose метод, когда блок заканчивается.

Комментарии:

1. @Flynn1179 — большинство пространств имен были удалены, НО в REQUEST_GROUP все еще есть xmlns:q1=»Com.Foo.Request», и в качестве побочного продукта всем узлам предшествует <q1:xxx

2. Я не вижу никакой ссылки на q1 пространство имен в вопросе.. откуда это берется?

3. @SPATEN чтобы исправить это, также добавьте ns.Add("", "Com.Foo.Request"); — тогда пространство имен будет без псевдонима.

4. @Flynn1179 — XmlSerializer использует его как псевдоним для «Com.Foo.Request»; по умолчанию он присваивает псевдонимы всему, что ему нужно, на случай, если они понадобятся несколько раз

5. Ах да, забыл об этом. Извините. Я обновлю ответ.

Ответ №2:

Если вы просто хотите удалить псевдонимы пространства имен, то, как уже показано, вы можете использовать XmlSerializerNamespaces принудительное XmlSerializer использование пространства имен явно (т.Е. xmlns="blah" ) для каждого элемента, вместо объявления псевдонима и использования псевдонима вместо него.

Однако, независимо от того, что вы делаете с псевдонимами, основное имя этого элемента находится REQUEST_GROUP в Com.Foo.Request пространстве имен. Вы не можете удалить пространство имен полностью без того, чтобы это не представляло собой критическое изменение базовых данных — т. Е. Кто-то где-то получит исключение (из-за получения данных, которых оно не ожидало, особенно REQUEST_GROUP в корневом пространстве имен). В терминах C # это разница между System.String и My.Custom.String — конечно, они оба вызываются String , но это всего лишь их локальное имя.

Если вы хотите удалить все следы пространства имен, то прагматичным вариантом было бы отредактировать Namespace=... записи из [XmlRoot(...)] и [XmlType(...)] (плюс где-либо еще, что не показано в примере).

Если типы находятся вне вашего контроля, вы также можете сделать это во время выполнения с помощью XmlAttributeOverrides — но предостережение: если вы создаете XmlSerializer используя XmlAttributeOverrides , вы должны кэшировать и повторно использовать его — иначе ваша AppDomain произойдет утечка (в этом режиме сборки создаются «на лету» для каждого сериализатора, и сборки не могут быть выгружены).