简体   繁体   中英

XmlSerializer filter by namespace

I am trying to deserialise an RSS 2.0 feed and i would like to take into account some of the iTunes extensions, but not have to bake them directly into the main class.

With the XML deserialiser in C# would something like the following be possible?

public class RssChannel
{
    [XmlElement("title")]
    public string Title { get; set; }

    [XmlElement("link")]
    public string Link { get; set; }

    ....

    [XmlElement(Namespace = "itunes")]
    public iTunesExtensions iTunes { get; set; }
}

public class iTunesExtensions 
{
    [XmlElement("category")]
    public string[] Categories { get; set; }
}

Which i am hoping would parse something like:

<channel>
    <itunes:category text="Society & Culture"/>
    <itunes:category text="Society & Culture"/>
    <itunes:category text="Society & Culture"/>
</channel>

Is it possible to do something like this where it is more modular? Or am i stuck baking it into the main class?

bizzehdee,

In order to set the first level to "", you would need to set it as the root and name of your class:

[XmlRoot("channel")]
public class channel

I will keep it as RssChannel, for the following examples.

I am assuming you intend to use more platforms than iTunes, so iTunes still has its own class. The way to do this, with less code, is to use a list instead of an array:

public List<iTunes> iTunes;

Categories will have its own class, so that you can use categories with any platform. Notice the use of XmlAttribute. This will include the name of the category in the same line:

public class iTunes 
{
    public List<Category> Categories { get; set; }
}

public class Category
{
    [XmlAttribute("category")]
    public string category { get; set; }
}

You can use a static class to help you serialize and deserialize the data. Here are two methods in a static class that will help:

// Save XML data.
public static void SaveData(ref RssChannel instance) {}

// Retrieve XML data.
public static RssChannel DeserializeData() {}

The best way to use these methods is to first get an instance of the RssChannel with the DeserializeData() method, like:

RssChannel foo = StaticClassName.DeserializeData();

Make your changes to it, then save that instance by passing it as a reference to the SaveData() method, like:

SaveData(ref foo);

Here is a full working example:

public static class XML
{
    // Serializes the passed instance of RssChannel into XML file, and saves to runtime memory.
    public static void SaveData(ref RssChannel instance)
    {
        // Objects:
        StreamWriter sw = new StreamWriter("yourXmlFile.xml");
        XmlSerializer serializer = new XmlSerializer(typeof(RssChannel));

        // Save data.
        serializer.Serialize(sw, instance);
        sw.Close();
    }

    // Deserializes data from the XML file, and returns the instance.
    public static RssChannel DeserializeData()
    {
        // Objects:
        RssChannel channelData = new RssChannel();
        XmlSerializer serializer = new XmlSerializer(typeof(RssChannel));
        List<iTunes> iTunesList = new List<iTunes>();

        if (File.Exists("yourXmlFile.xml"))
        {
            FileStream stream = new FileStream("yourXmlFile.xml", FileMode.Open);

            // Deserialize data.
            channelData = (RssChannel)serializer.Deserialize(stream);
            stream.Close();

            // Add data from deserialized iTunes list to list instance.
            if (channelData.iTunesList != null)
                iTunesList = channelData.iTunesList;
        }

        // Add data to RootData object lists.
        channelData.iTunesList = iTunesList;

        return channelData;
    }
}

[XmlRoot("RssChannel")]
public class RssChannel
{
    [XmlAttribute("Title")]
    public string Title; // { get; set; }

    [XmlAttribute("Link")]
    public string Link; // { get; set; }

    public List<iTunes> iTunesList; // { get; set; }
}

public class iTunes 
{
    public List<Category> Categories; // { get; set; }
}

public class Category
{
    [XmlAttribute("category")]
    public string category; // { get; set; }
}

You can use the classes and static methods like this:

private void AnyMethod()
{
    // To get an instance of your RssChannel class with all the data:
    RssChannel rssChannel = XML.DeserializeData();

    // Do anything with the data. Example below:
    iTunes newITunes = new iTunes();
    List<Category> categoryList = new List<Category>();

    Category newCategory1 = new Category(); // Create new categories.
    newCategory1.category = "Allegro";
    categoryList.Add(newCategory1);

    Category newCategory2 = new Category();
    newCategory2.category = "Prestissimo";
    categoryList.Add(newCategory2);

    newITunes.Categories = categoryList; // Add the categories to list.

    rssChannel.iTunesList.Add(newITunes); // Add that list to iTunes list.

    // Now, to save the data, pass a reference to the instance we just worked on:
    XML.SaveData(ref rssChannel);
}

This will produce a file that looks like:

<?xml version="1.0" encoding="utf-8"?>
<RssChannel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <iTunesList>
    <iTunes>
      <Categories>
        <Category category="Allegro" />
        <Category category="Prestissimo" />
      </Categories>
    </iTunes>
  </iTunesList>
</RssChannel>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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