XML attribute not getting namespace prefix

16,989

Solution 1

I did some research may be following answer helps

For Attributes to have namespace prefix you have to specify a different namespace tag other than what you have specified http://foo. Following code hopefully will solve your issue. In the code i have remove the namespace for elements and added only for the attribute.

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

Solution 2

This may be a bug in XmlSerializer.

As you have noticed, even when XmlAttributeAttribute.Namespace is set explicitly, the attribute will not be prefixed in certain situations. From testing, this appears to happen when the attribute namespace happens to be the same as the namespace of the element currently being written.

For instance:

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

Serializes to the following XML:

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

And since the attribute is unprefixed, it's actually not in any namespace, as is explained in the XML standard: The namespace name for an unprefixed attribute name always has no value.

However, the following:

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

Serializes with the attribute correctly prefixed:

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

The workaround is to explicitly set [XmlAttribute(Form = XmlSchemaForm.Qualified)]. Thus:

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

Serializes to

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

as required.

Share:
16,989
Devin Goble
Author by

Devin Goble

I'm a full stack developer specializing in the .NET ecosystem. I dabble in front end technologies such as Aurelia and Vue. I'm passionate about technology, but I'm just as happy working and playing outdoors. I like to build things, whether it's writing software, or constructing a building. I just like the satisfaction that comes from the seeing the process through to the end.

Updated on June 05, 2022

Comments

  • Devin Goble
    Devin Goble almost 2 years

    I need to generate the following XML during serialization: (fragment)

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

    The class in question looks like this:

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

    It appears that the serializer is noticing that the namespace is already declared in an xmlns: at the root and is ignoring my attribute. I also tried the following:

    [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; }
    
    }
    

    This results in the following 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>
    

    Which is not what I want. The element shouldn't be prefixed, the attribute should be. What is needed to get the serializer to understand what I want?