#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
произойдет утечка (в этом режиме сборки создаются «на лету» для каждого сериализатора, и сборки не могут быть выгружены).