2013-12-18 3 views
2

Мне нужно создать следующий XML во время сериализации: (фрагмент)XML атрибут не получает префикс пространства имен

<IncidentEvent a:EventTypeText="Beginning" xmlns:a="http://foo"> 
    <EventDate>2013-12-18</EventDate> 
    <EventTime>00:15:28</EventTime> 
</IncidentEvent> 

Класс в вопросе выглядит следующим образом:

public class IncidentEvent 
{ 
    public string EventDate { get; set; } 
    public string EventTime { get; set; } 

    [XmlAttribute("EventTypeText", Namespace = "http://foo")] 
    public string EventTypeText { get; set; } 

} 

Оказывается, что сериализатором замечает, что пространство имен уже объявлено в xmlns: в корне и игнорирует мой атрибут. Я также попытался следующие:

[XmlRoot(Namespace = "http://foo")] 
public class IncidentEvent 
{ 
    public string EventDate { get; set; } 
    public string EventTime { get; set; } 

    private XmlSerializerNamespaces _Xmlns; 

    [XmlNamespaceDeclarations] 
    public XmlSerializerNamespaces Xmlns 
    { 
     get 
     { 
      if (_Xmlns == null) 
      { 
       _Xmlns = new XmlSerializerNamespaces(); 
       _Xmlns.Add("ett", "http://foo"); 
      } 

      return _Xmlns; 
     } 

     set 
     { 
      _Xmlns = value; 
     } 
    } 


    [XmlAttribute("EventTypeText", Namespace = "http://foo")] 
    public string EventTypeText { get; set; } 

} 

Это приводит к следующему XML:

<ett:IncidentEvent EventTypeText="Beginning" xmlns:ett="http://foo"> 
    <ett:EventDate>2013-12-18</ett:EventDate> 
    <ett:EventTime>00:15:28</ett:EventTime> 
    </ett:IncidentEvent> 

Который не то, что я хочу. Элемент не должен быть префиксным, атрибут должен быть. Что нужно, чтобы заставить сериализатор понять, что я хочу?

ответ

0

Я сделал некоторые исследования может быть следующим ответом помогает

Для атрибутов, чтобы иметь префикс пространства имен вам нужно указать другой тег пространства имен, отличный от того, что вы указали http://foo. Следующий код, надеюсь, решит вашу проблему. В коде я удаляю пространство имен для элементов и добавляю только для атрибута.

public class IncidentEvent 
{ 
    public string EventDate { get; set; } 
    public string EventTime { get; set; } 

    [XmlAttribute("EventTypeText", Namespace = "http://foo")] 
    public string EventTypeText { get; set; } 

} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     IncidentEvent xmlObj = new IncidentEvent() 
     { 
      EventDate = "2012.12.01", 
      EventTime = "1:00:00", 
      EventTypeText = "Beginining" 
     }; 
     XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
     ns.Add("ett", "http://foo"); 
     XmlSerializer serializer = new XmlSerializer(typeof(IncidentEvent)); 
     serializer.Serialize(Console.OpenStandardOutput(), xmlObj, ns); 
     Console.WriteLine(); 
    } 
} 

http://www.w3.org/TR/2009/REC-xml-names-20091208/#defaulting

+0

Это, похоже, разваливается, если вам нужно сериализовать этот объект как дочерний объект другого объекта. Он работал нормально, когда я тестировал его по одному сценарию, но я забыл о другом. Тем не менее, хороший ответ. – kettch

0

Пространства имен предназначены для того, чтобы различать два элемента XML, имеющих одинаковое имя. Поскольку разные элементы XML могут иметь одно и то же имя атрибута, но другое значение. Таким образом, нет никакого преимущества наличия тега пространства имен для атрибута, поскольку атрибуты XML считаются частью «пространства имен элементов». В вашем примере

<ett:IncidentEvent EventTypeText="Beginning" xmlns:ett="http://foo"> 
    <ett:EventDate>2013-12-18</ett:EventDate> 
    <ett:EventTime>00:15:28</ett:EventTime> 
</ett:IncidentEvent> 

EventTypeText является частью пространства имен эфф: IncidentEvent Пожалуйста, обратитесь к http://www.w3.org/TR/REC-xml-names/ для Пространства имен XML

+0

XML должен проверять XSD, который у меня отсутствует. Все, что мне нужно сделать, это написать XML, который соответствует схеме. Мой первый фрагмент написан вручную, но он проверяет. Мне просто нужно выяснить, как заставить сериализатор делать то же самое. – kettch

0

Я дам ККД кредит за ответ, но я обнаружил еще один сценарий, который до сих пор вызывает вопросы. По-видимому, если объект, который будет сериализован, является дочерним объектом другого объекта, если пространство имен родительского объекта совпадает с дочерним, сериализатор предполагает, что вам не нужно явно объявлять пространство имен для дочернего элемента.

public class IncidentEvent : IXmlSerializable 
{ 
    public string EventDate { get; set; } 
    public string EventTime { get; set; } 
    public string EventTypeText { get; set; } 

    public System.Xml.Schema.XmlSchema GetSchema() 
    { 
     return null; 
    } 

    public void ReadXml(System.Xml.XmlReader reader) 
    { 
     return null; 
    } 

    public void WriteXml(System.Xml.XmlWriter writer) 
    { 
     writer.WriteAttributeString("ex", "EventTypeText", "http://foo", EventTypeText); 
    } 
} 

Реализуя IXmlSerializable, я могу вручную выписывать элементы и атрибуты в точности так, как мне нужно. Поскольку это односторонний экспорт, мне не нужно было реализовывать ничего, кроме метода WriteXml.

Я все еще не уверен, является ли это лучшим способом, но он работает на данный момент.

3

Это может быть ошибка в XmlSerializer.

Как вы заметили, даже если XmlAttributeAttribute.Namespace установлен явно, атрибут не будет префикс в определенных ситуациях. Из тестирования это происходит, когда пространство имен атрибутов оказывается таким же, как пространство имен элемента, который в настоящее время записывается.

Например:

[XmlRoot(Namespace = "http://foo")] 
public class IncidentEvent 
{ 
    [XmlAttribute("EventTypeText", Namespace = "http://foo")] 
    public string EventTypeText { get; set; } 
} 

Сериализует к следующему XML:

<q1:IncidentEvent EventTypeText="an attribute" xmlns:q1="http://foo" /> 

И так как атрибут без префикса, это на самом деле не в любом пространстве имен, как объяснено in the XML standard: Имя пространства имен для имени без префиксов всегда не имеет значения.

Однако следующее:

[XmlRoot(Namespace = "http://foo")] 
public class IncidentEvent 
{ 
    [XmlAttribute("EventTypeText", Namespace = "http://bar")] 
    public string EventTypeText { get; set; } 
} 

Сериализует с атрибутом правильно приставкой:

<q1:IncidentEvent p1:EventTypeText="an attribute" xmlns:p1="http://bar" xmlns:q1="http://foo" /> 

Обходной является явно установить [XmlAttribute(Form = XmlSchemaForm.Qualified)]. Таким образом:

[XmlRoot(Namespace = "http://foo")] 
public class IncidentEvent 
{ 
    [XmlAttribute("EventTypeText", Namespace = "http://foo", Form = XmlSchemaForm.Qualified)] 
    public string EventTypeText { get; set; } 
} 

Сериализует в

<q1:IncidentEvent q1:EventTypeText="an attribute" xmlns:q1="http://foo" /> 

по мере необходимости.

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