2009-04-06 3 views
2

У меня возникла ситуация, когда у меня есть xml-файл, который я не хочу изменять. Функция AddAnnotation в классе XElement предоставляет возможность добавлять данные только для памяти, которые не являются сериализованными, а не частью XML.XML-сериализация аннотаций

Я хочу, чтобы сохранить эти аннотации (например: в другой файл xml), а затем десериализовать как xml, так и аннотации, чтобы получить тот же самый объект, который у меня был.

Я не хочу менять исходный xml, и именно по этой причине я использую аннотации.

Подводя итог, хочу добавить пользовательские данные в XML-файл. Эти данные не будут частью xml, когда я его сериализую, или он будет частью xml, но я бы мог легко получить исходный xml.

Есть ли у вас рекомендации, как я могу это сделать?

Редактировать: Должен ли я использовать инструкции обработки xml? Инструкции по обработке, предназначенные для такого использования?

ответ

2

Это звучит для меня, как простой подход будет использовать регулярные узлы, но в другой XML-пространства - т.е.

<foo standardAttrubute="abc" myData:customAttribute="def"> 
    <standardElement>ghi</standardElement > 
    <myData:customElement>jkl</myData:customElement> 
</foo> 

(где myData является xmlns псевдоним для пространства имен-URI)

Во многих случаях считыватели проверяют только данные в их пространства имен (или пространство имен по умолчанию/пустое пространство) - значения в пользовательских пространствах имен обычно пропускаются.

Чтобы получить пакет исходного xml, одним простым подходом было бы запустить его через xslt, который будет уважать только исходное/исходное пространство имен.


XNamespace myData = XNamespace.Get("http://mycustomdata/"); 
XElement el = new XElement("foo", 
    new XAttribute(XNamespace.Xmlns + "myData", myData.NamespaceName), 
    new XAttribute("standardAttribute", "abc"), 
    new XAttribute(myData + "customAttribute", "def"), 
    new XElement("standardElement", "ghi"), 
    new XElement(myData + "customAttribute", "jkl")); 
string s = el.ToString(); 

Чтобы удалить эти данные из XElement, возможно:

static void Strip(XElement el, XNamespace ns) { 
     List<XElement> remove = new List<XElement>(); 
     foreach (XElement child in el.Elements()) { 
      if (child.Name.Namespace == ns) { 
       remove.Add(child); 
      } else { 
       Strip(child, ns); 
      } 
     } 
     remove.ForEach(child => child.Remove()); 

     foreach (XAttribute child in 
      (from a in el.Attributes() 
      where a.Name.Namespace == ns 
      select a).ToList()) { 
      child.Remove(); 
     } 
    } 
+0

Звуки интересно ... Можете ли вы привести пример (на самом деле два примера), как Я могу загрузить xml с помощью XElement, с и без пользовательского атрибута? –

+0

Созданное дополнение - это то, что вы имели в виду? Или что-то другое? –

+0

Нет. Я знаю, как создать xml. Я не знаю, как загрузить его без пользовательских данных. TNX! –

1

Оригинальный вопрос используется слово "Serialize", но затем также упоминается XElement и аннотацию. Для меня это две разные вещи.

Если вы действительно хотите использовать XmlSerializer:
Что бы я сделал это использовать XmlAttributeOverrides, чтобы дифференцировать сериализации. С помощью XmlAttributeOverrides вы можете программно, во время выполнения, переопределять атрибуты сериализации xml, которые украшают ваши типы.

В вашем типе у вас может быть поле/свойство, предназначенное для хранения аннотации/документации. Украсьте это с помощью XmlIgnore. Затем создайте один экземпляр XmlSerializer, который не примет никаких переопределений. Аннотации не будут сериализованы или де-сериализованы. Создайте еще один экземпляр XmlSerializer для этого типа, используя объект XmlAttributeOverrides. Укажите переопределение для свойства XmlIgnore'd (используйте XmlElementAttribute), а также переопределите любые атрибуты для любого из других членов (используйте XmlIgnore = true).

Сериализуйте экземпляр дважды, один с каждым сериализатором.


Edit: вот код:

public class DTO 
{ 
    [XmlIgnore] 
    public string additionalInformation; 

    [XmlElement(Order=1)] 
    public DateTime stamp; 

    [XmlElement(Order=2)] 
    public string name; 

    [XmlElement(Order=3)] 
    public double value; 

    [XmlElement(Order=4)] 
    public int index; 
} 



public class OverridesDemo 
{ 
    public void Run() 
    { 
     DTO dto = new DTO 
      { 
       additionalInformation = "This will bbe serialized separately", 
       stamp = DateTime.UtcNow, 
       name = "Marley", 
       value = 72.34, 
       index = 7 
      }; 


     // --------------------------------------------------------------- 
     // 1. serialize normally 
     // this will allow us to omit the xmlns:xsi namespace 
     var ns = new XmlSerializerNamespaces(); 
     ns.Add("", ""); 

     XmlSerializer s1 = new XmlSerializer(typeof(DTO)); 

     var builder = new System.Text.StringBuilder(); 
     var settings = new XmlWriterSettings { OmitXmlDeclaration = true, Indent= true }; 

     Console.WriteLine("\nSerialize using the in-line attributes: "); 
     using (XmlWriter writer = XmlWriter.Create(builder, settings)) 
     { 
      s1.Serialize(writer, dto, ns); 
     } 
     Console.WriteLine("{0}",builder.ToString()); 
     Console.WriteLine("\n");    
     // --------------------------------------------------------------- 

     // --------------------------------------------------------------- 
     // 2. serialize with attribute overrides 
     // use a non-empty default namespace 
     ns = new XmlSerializerNamespaces(); 
     string myns = "urn:www.example.org"; 
     ns.Add("", myns); 

     XmlAttributeOverrides overrides = new XmlAttributeOverrides(); 

     XmlAttributes attrs = new XmlAttributes(); 
     // override the (implicit) XmlRoot attribute 
     XmlRootAttribute attr1 = new XmlRootAttribute 
      { 
       Namespace = myns, 
       ElementName = "DTO-Annotations", 
      }; 
     attrs.XmlRoot = attr1; 

     overrides.Add(typeof(DTO), attrs); 
     // "un-ignore" the first property 
     // define an XmlElement attribute, for a type of "String", with no namespace 
     var a2 = new XmlElementAttribute(typeof(String)) { ElementName="note", Namespace = myns }; 

     // add that XmlElement attribute to the 2nd bunch of attributes 
     attrs = new XmlAttributes(); 
     attrs.XmlElements.Add(a2); 
     attrs.XmlIgnore = false; 

     // add that bunch of attributes to the container for the type, and 
     // specifically apply that bunch to the "additionalInformation" property 
     // on the type. 
     overrides.Add(typeof(DTO), "additionalInformation", attrs); 

     // now, XmlIgnore all the other properties 
     attrs = new XmlAttributes(); 
     attrs.XmlIgnore = true;  
     overrides.Add(typeof(DTO), "stamp", attrs); 
     overrides.Add(typeof(DTO), "name", attrs); 
     overrides.Add(typeof(DTO), "value", attrs); 
     overrides.Add(typeof(DTO), "index", attrs); 

     // create a serializer using those xml attribute overrides 
     XmlSerializer s2 = new XmlSerializer(typeof(DTO), overrides); 

     Console.WriteLine("\nSerialize using the override attributes: "); 
     builder.Length = 0; 
     using (XmlWriter writer = XmlWriter.Create(builder, settings)) 
     { 
      s2.Serialize(writer, dto, ns); 
     } 
     Console.WriteLine("{0}",builder.ToString()); 
     Console.WriteLine("\n");    
     // --------------------------------------------------------------- 
    } 
} 

выход, используя рядный атрибуты:

<DTO> 
    <stamp>2009-06-30T02:17:35.918Z</stamp> 
    <name>Marley</name> 
    <value>72.34</value> 
    <index>7</index> 
</DTO> 

выход, используя переопределение атрибутов:

<DTO-Annotations xmlns="urn:www.example.org"> 
    <note>This will bbe serialized separately</note> 
</DTO-Annotations> 
+0

Я не уверен, что последовал. Можете ли вы предоставить фрагмент? Тпх ... –

 Смежные вопросы

  • Нет связанных вопросов^_^