简体   繁体   English

XML 普通字符串的属性

[英]XML Attribute on Plain String

I'd like to generate some XML like the following with C# code.我想用 C# 代码生成一些 XML,如下所示。

<card>
 <name>Cool Card</name>
 <set rarity="common">S1</set>
</card>

I have something like this.我有这样的东西。

public class card
{
    public string name = "Cool Card";
    [XmlAttribute]
    public string rarity = "common";
    public string set = "S1";
}

public static void WriteXml()
{
    var serializer = new XmlSerializer(typeof(card));
    var myCard = new();

    using var sw = new StringWriter();
    serializer.Serialize(sw, myCard);
    XDocument doc = XDocument.Parse(sw.ToString());
    XmlWriterSettings xws = new();
    xws.OmitXmlDeclaration = true;
    xws.Indent = true;
    using var xw = XmlWriter.Create(path, xws);
    doc.Save(xw);
}

The problem is that this doesn't add the "rarity" attribute to the "set" value.问题是这不会将“稀有度”属性添加到“设置”值。 Trying to add [XmlAttribute] adds it to the parent element rather than the next sibling element and I can't figure out how to get it on a plain string element, so at present my output looks like.尝试添加[XmlAttribute]会将其添加到父元素而不是下一个同级元素,我无法弄清楚如何在普通字符串元素上获取它,所以目前我的 output 看起来像。

<card rarity="common">
 <name>Cool Card</name>
 <set>S1</set>
</card>

The XML example doc shows an example of how to set the attribute on an element, but only one with nested fields and not one that's a plain string. XML 示例文档显示了如何在元素上设置属性的示例,但只有一个具有嵌套字段,而不是一个纯字符串。 Is it possible to add an attribute to a plain old string element in XML like my first posted example demonstrates?是否可以像我第一个发布的示例演示的那样向 XML 中的普通旧字符串元素添加属性?

Try this:尝试这个:

public class card
{
    public string name = "Cool Card";
    public Set set = new();
}

public class Set
{
    [XmlText]
    public string value = "S1";
    [XmlAttribute]
    public string rarity = "common";
}

If you think about it there is no other way the xml attribute can be applied only to the element it is declared in. So you need to move it into another class. When you do this new property for value is required and that one needs to be flattened as value node is not required for that you need XmlText attribute.如果您考虑一下,没有其他方法可以将 xml 属性仅应用于声明它的元素。因此您需要将其移动到另一个 class 中。当您执行此新属性时,值是必需的,并且需要由于不需要 XmlText 属性,因此不需要值节点。

在此处输入图像描述

The cleanest option in this case is implement IXmlSerializable:在这种情况下,最干净的选择是实施 IXmlSerializable:

public class card : IXmlSerializable
{
    public string name = "Cool Card";
    public string rarity = "common";
    public string set = "S1";

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

    public void ReadXml(System.Xml.XmlReader reader)
    {
        reader.ReadStartElement(nameof(card));

        while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
        {
            if (reader.Name == nameof(name))
            {
                this.name = reader.ReadElementContentAsString();
            }
            else if (reader.Name == nameof(set))
            {
                this.rarity = reader.GetAttribute(nameof(rarity));
                this.set = reader.ReadElementContentAsString();
            }
        }

        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteElementString(nameof(name), this.name);

        writer.WriteStartElement(nameof(set));
        writer.WriteAttributeString(nameof(rarity), this.rarity);
        writer.WriteString(this.set);
        writer.WriteEndElement();                
    }
}

If your class is big and you only need do a bit change in the XML, sometimes implement IXmlSerializable is a mess (you must save all the properties and only in one or two, do a bit change).如果你的 class 很大,你只需要在 XML 中做一点改变,有时实现 IXmlSerializable 就是一团糟(你必须保存所有属性,只保存一两个属性,做一点改变)。 In these cases, you can use attributes and some small helpers classes to get same results.在这些情况下,您可以使用属性和一些小的助手类来获得相同的结果。 The idea is tell to XML serializer that don't serialize some property and use another fake property to do the serialization.这个想法是告诉 XML 序列化器不序列化某些属性并使用另一个假属性来进行序列化。

For example, create a Set class with your desired XML structure:例如,使用所需的 XML 结构创建一个 Set class:

public class XmlSet
{
    private readonly card _card;

    public XmlSet()
    {
        this._card = new card();
    }

    public XmlSet(card card)
    {
        this._card = card;
    }

    [XmlText]
    public string set
    {
        get { return this._card.set; }
        set { this._card.set = value; }
    }

    [XmlAttribute]
    public string rarity
    {
        get { return this._card.rarity; }
        set { this._card.rarity = value; }
    }
}

It's only a wrapper, with the XML sttributes that you want.它只是一个包装器,具有您想要的 XML 属性。 You get/set the values from/to your card object.您从card object 获取/设置值。

Then, in your card class, Ignore the set property and serialize the fake property:然后,在你的卡 class 中,忽略设置属性并序列化假属性:

public class card
{
    public string name = "Cool Card";
    [XmlIgnore]
    public string rarity = "common";
    [XmlIgnore]
    public string set = "S1";

    // Added to serialization
    private XmlSet _xmlSetNode;

    [XmlElement("set")]
    public XmlSet XmlSet
    {
        get
        {
            this._xmlSetNode = this._xmlSetNode ?? new XmlSet(this);
            return this._xmlSetNode;
        }
        set { this._xmlSetNode = value; }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM