Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
159 views
in Technique[技术] by (71.8m points)

c# - Parse xml with varying Key

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
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...