dayy
dayy

Reputation: 43

Pass string variable to XmlAttribute of XMLSerializer

Let's say I have the following code, and want to serialize into the XML below the code:

class Human
{
    [XmlElement("OwnedObjects")]
    public List<WorldObjects> ownedObjects;
}

class WorldObjects
{
    [XmlIgnore]
    public string type;
    [XmlAttribute(type)]
    public string name;

    public WorldObjects(string _type, string _name)
    {
        type = _type;
        name = _name;
    }
}

Human bob = new Human;
bob.ownedObjects = new List<WorldObjects>;
bob.ownedObjects.Add(new WorldObjects(drink, tea));

// Serialize

XML:

<Human>
    <OwnedObjects drink="tea" />
</Human>

The line [XmlAttribute(type)] will result in an error.

Is there anyway to change the attribute name by passing on a string variable?

Thank you in advance.

EDIT: I must apologise I overlooked such an easy solution. Thank you for your answers. Also, thank you Ben and dbc for suggesting an improvement on the design.

Upvotes: 4

Views: 1398

Answers (1)

dbc
dbc

Reputation: 117016

You can use [XmlAnyAttribute] for this purpose. It specifies that the member (a field that returns an array of XmlAttribute objects) can contain any XML attributes. Note that a property can be used as well as a field to construct and return a single attribute with the required name and value:

public class WorldObjects
{
    [XmlAnyAttribute]
    public XmlAttribute [] Attributes
    {
        get
        {
            var attr = new XmlDocument().CreateAttribute(XmlConvert.EncodeLocalName(type));
            attr.Value = name;
            return new[] { attr };
        }
        set
        {
            var attr = (value == null ? null : value.SingleOrDefault());
            if (attr == null)
                name = type = string.Empty;
            else
            {
                type = XmlConvert.DecodeName(attr.Name);
                name = attr.Value;
            }
        }
    }

    [XmlIgnore]
    public string name;

    [XmlIgnore]
    public string type;

    // XmlSerializer required parameterless constructor
    public WorldObjects() : this(string.Empty, string.Empty) { }

    public WorldObjects(string _type, string _name)
    {
        type = _type;
        name = _name;
    }
}

XmlConvert.EncodeLocalName() is required in cases where the type string is not a valid XML name. A valid XML name must, for instance, begin with a letter, not a number.

Example fiddle.

However, using fixed attributes such as type="drink" name="tea" may make it easier to create an XML schema down the road if required, so you might rethink your design. [XmlAnyAttribute] corresponds to the schema element xsd:anyAttribute which allows for any number of attributes of any name to appear. You would want to specify that there must be exactly one attribute of any name for your <OwnedObjects> element.

Upvotes: 3

Related Questions