Parse xml with varying Key

2019-09-19 09:26发布

I'm trying to parse the XML below:

<plist version="1.0">
<array>
    <dict>
        <key>SubTitle</key>
        <array>
            <dict>
                <key>Values</key>
                <array>
                    <string>D1</string>
                    <string>D2</string>
                </array>
                <key>Title</key>
                <string>Chapter One</string>
                <key>supportsEdit</key>
                <true/>
            </dict>
            <dict>
                <key>Values</key>
                <array>
                    <string>DC1</string>
                    <string>DC2</string>
                </array>
                <key>Title</key>
                <string>Chapter Two</string>
                <key>supportsEdit</key>
                <true/>
            </dict>
        </array>
        <key>MainTitle</key>
        <string>Science</string>
    </dict>
    <dict>
        <key>SubTitle</key>
        <array>
            <dict>
                <key>Values</key>
                <array>
                    <string>CD1</string>
                    <string>CD2</string>
                </array>
                <key>Title</key>
                <string>Chapter One</string>
                <key>supportsEdit</key>
                <true/>
            </dict>
            <dict>
                <key>Values</key>
                <array>
                    <string>DDC1</string>
                    <string>DDC2</string>
                </array>
                <key>Title</key>
                <string>Chapter Two</string>
                <key>supportsEdit</key>
                <true/>
            </dict>
        </array>
        <key>MainTitle</key>
        <string>Physics</string>
    </dict>

    /// here is where i get the error
    <dict>
        <key>Values</key>
        <array>
                            <string>CD1</string>
                <string>CD2</string>
                            <string>DDC1</string>
            <string>DDC2</string>
                            <string>DC1</string>
                        <string>DC2</string>
        </array>
        <key>Title</key>
        <string>Random Values</string>
        <key>supportsEdit</key>
        <true/>
    </dict>

This is my parser:

XDocument doc = XDocument.Load(FileName);

Dictionary<string, List<Chapter>> plistData =
        doc.Root.Element("array").Elements("dict")
            .Select(GetValues)
            .ToDictionary(v => (string)v["MainTitle"],
                          v => v["SubTitle"]
                          .Elements("dict").Select(ParseMyObject).ToList());

static Dictionary<string, XElement> GetValues(XElement dict)
{
    return dict.Elements("key")
               .ToDictionary(k => (string)k, k => (XElement)k.NextNode);
}

static Chapter ParseMyObject(XElement dict)
{
    var values = GetValues(dict);

    return new Topic
    {
        Title = (string)values["Title"],
        FileNames = values["Values"].Elements().Select(s =>(string)s).ToList()
    };
}

Please see the comment that I have added in the XML file. The issue here is that the first two dicts have key as SubTitle with array but the third dict does not have any key.

How should I parse this?

I am working on windows Phone 8 and am trying to parse the XML and populate the data in a UI. This is what my UI looks like: I have 3 buttons: Science, Physics and Random.

When I click on “Science” I get “Chapter one and chapter two”; if I click on either chapter one or chapter two I get all values from the XML.

But when I click on “Random” I need to get only values from the XML.

EDIT

to print values:

foreach (var value in plistData)
{
    topicList.Add(value.Key);
    Debug.WriteLine(" Main title is "+value.Key);
    if (!value.Key.Equals("Random Values"))
    {
        List<Topic> listOfSubTopics = plistData[value.Key];
        for (int j = 0; j < listOfSubTopics.Count; j++)
        {
            Debug.WriteLine("sub title " + listOfSubTopics[j].Title);
            for (int i = 0; i < listOfSubTopics[j].FileNames.Count; i++)
            {
                Debug.WriteLine("Values is" + listOfSubTopics[j].FileNames[i]);
            }
        }
    }
    else
    {
       // here i want to print values of Random Values
    }

1条回答
倾城 Initia
2楼-- · 2019-09-19 10:23

For debugging purposes I split your collection in two steps:

        var first = doc
            .Root
            .Element("array")
            .Elements("dict")
            .Select(GetValues);

       var plistData = first
            .ToDictionary(
                v => v.ContainsKey("MainTitle")?
                        (string) v["MainTitle"]:
                        (string) v["Title"],
                 v => (v.ContainsKey("SubTitle")?
                        v["SubTitle"]
                        .Elements("dict")
                        .Select(ParseMyObject) :
                        ParseMyString(v["Values"])
                        )
                        .ToList());

Helper for the last plist structure

    static List<Chapter> ParseMyString(XElement dict)
    {

        return new List<Chapter>
            {
                new Chapter
                    {
                        Title = "some values",
                        FileNames = dict.Elements().Select(s => (string) s).ToList()
                    }
            };
    } 

I added a check when you create the dictionary element if the key MainTitle actually exists. If it doesn't I add a default key. The same mechanism is applied to SubTitle, if that doesn't exist a null value is supplied.

查看更多
登录 后发表回答