Question

J'ai une situation où j'ai un fichier xml que je ne veux pas modifier. La fonction AddAnnotation en classe XElement fournit une option pour ajouter des données de la mémoire seule qui n'est pas sérialisés et ne fait pas partie du XML.

Je veux être en mesure d'enregistrer ces annotations (par exemple: à un autre fichier xml), puis à la fois désérialiser le XML et les annotations afin d'obtenir le même objet que j'avais.

Je ne veux pas changer le code XML d'origine et c'est la raison pour laquelle j'utilise des annotations.

Pour résumer, je veux être en mesure d'ajouter des données personnalisées dans un fichier xml. Ces données ne sera pas une partie du xml quand je sérialiser ou ce sera une partie du xml mais je serais en mesure de récupérer le xml facilement d'origine.

Avez-vous une recommandation que je peux faire une telle chose?

Modifier Dois-je utiliser des instructions de traitement XML? Les instructions sont-traitement destiné à ce type d'utilisation?

Était-ce utile?

La solution

Il me semble que l'approche la plus simple serait d'utiliser des nœuds réguliers, mais dans un espace de noms XML différent -. I.e.

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

(où myData est un alias de l'espace de noms pour xmlns-uri)

Dans de nombreux cas, les lecteurs ne sont vérifier des données dans leur espace de nom (ou l'espace de noms par défaut / blanc) -. Les valeurs personnalisées dans les espaces de noms sont généralement ignorés

Pour emballer le XML d'origine, une approche simple serait de l'exécuter par un xslt qui ne respecte que la valeur par défaut / espace de noms d'origine.


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();

Pour supprimer ces données d'un XElement, peut-être:

    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();
        }
    }

Autres conseils

La question initiale a utilisé le mot « sérialisation » mais aussi mentionné XElement et l'annotation. Pour moi, ce sont deux choses différentes.

Si vous voulez vraiment utiliser XmlSerializer: Ce que je voudrais faire est d'utiliser XmlAttributeOverrides, pour différencier la sérialisation. Avec les XmlAttributeOverrides vous pouvez par programmation, lors de l'exécution, remplacer les attributs de sérialisation xml qui ornent vos types.

Dans votre type, vous pouvez avoir un champ / propriété qui est destiné à maintenir l'annotation / documentation. Décorez avec XmlIgnore que. Ensuite, créez une instance de XmlSerializer qui accepte aucun remplacement. L'annotation ne sera pas sérialisé ou désérialisé. Créer une autre instance du XmlSerializer pour ce type, en utilisant un objet XmlAttributeOverrides. Spécifier une valeur de remplacement pour la propriété XmlIgnore'd (utilisation XmlElementAttribute), ainsi que des remplacements pour tous les attributs de l'un des autres éléments (utilisation XmlIgnore = true).

sérialiser l'exemple deux fois, une à chaque sérialiseur.


Edit: voici le code:

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");            
        // ---------------------------------------------------------------
    }
}

sortie, en utilisant les attributs en ligne:

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

sortie, en utilisant les attributs de forçage:

<DTO-Annotations xmlns="urn:www.example.org">
  <note>This will bbe serialized separately</note>
</DTO-Annotations>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top