-->

xml parsing - code refactoring issue

2019-03-06 17:24发布

问题:

I have the following xml:

<?xml version="1.0" encoding="utf-8"?>
<RootData>
  <PassResult>
  <FirstOne>P1</FirstOne>
  <SecondOne>P2</SecondOne>
 <IsMale>false</IsMale>
</PassResult>
<TestResult>
  <MarkOne>100</MarkOne>
  <MarkTwo>50</MarkTwo>
  <Slope>30</Slope>
</TestResult>
<ToneTestResult>
  <TotalTime>2</TotalTime>
  <CorrectPercentage>90</CorrectPercentage>
</ToneTestResult>
<QuestionnaireResult Version="1">
  <Question Id="50">
   <Answer Id="B" />
 </Question>
  <Question Id="60">
   <Answer Id="A" />
 </Question>
 </QuestionnaireResult>
</RootData>

I have the following code which is not at all looking a good one. Lots of repeatative link queries. How can I refactor this code in a more structured way to fill "OutputData" object. I do not want to change it to XmlSerializer now :-(.

Sample code:

    // Gets the root element decendants
        var elementRootData = xDocument.Descendants("RootData");

        var xElements = elementRootData as IList<XElement> ?? elementRootData.ToList();


   // Read first leaf node "ProfileResult"
        var passResult = from xElement in xElements.Descendants("PassResult")
            select new
            {

                FirstOne = xElement.Element("FirstOne").GetValue(),
                SecondOne = xElement.Element("SecondOne").GetValue(),
                IsMale = xElement.Element("IsMale").GetValue()
            };


    // Read second leaf note
        var testResult = from xElement in xElements.Descendants("TestResult")
            select new
            {

                MarkOne = xElement.Element("MarkOne").GetValue(),
                MarkTwo = xElement.Element("MarkTwo").GetValue(),
                Slope = xElement.Element("Slope").GetValue()
            };


    // Update OutputData object
        var parseOutputData = new OutputData();

    foreach (var result in passResult)
        {
            parseOutputData.FirstOne = result.FirstOne;
            parseOutputData.SecondOne = result.SecondOne;
            parseOutputData.IsMale = result.IsMale.Equals("True");
        }

        foreach (var result in testResult)
        {
            parseOutputData.MarkOne = double.Parse(result.MarkOne);
            parseOutputData.MarkTwo = double.Parse(result.MarkTwo);
            parseOutputData.Slope = double.Parse(result.Slope);
        }

I have to write some more code like this to fill other elements data like ToneTestResult, QuestionnaireResult etc. Can someone suggest with a sample code?

Best regards,

回答1:

Given your XML is tiny, you probably don't have to worry too much about performance. You can just do the whole thing in one go, making use of the built in explicit conversions:

var data = new OutputData
{
    FirstOne = (string) doc.Descendants("FirstOne").Single(),
    SecondOne = (string) doc.Descendants("SecondOne").Single(),
    IsMale = (bool) doc.Descendants("IsMale").Single(),
    MarkOne = (double) doc.Descendants("MarkOne").Single(),
    MarkTwo = (double) doc.Descendants("MarkTwo").Single(),
    Slope = (double) doc.Descendants("Slope").Single()
};

As an aside, Descendants will never return anything implementing IList<XElement>, so you can definitely remove that.



回答2:

Try XML Linq

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);
            var root = doc.Elements("RootData").Select(x => new
            {
                passResults = x.Elements("PassResult").Select(y => new
                {
                    firstOne = (string)y.Element("FirstOne"),
                    secondOne = (string)y.Element("SecondOne"),
                    isMale = (Boolean)y.Element("IsMale")
                }).FirstOrDefault(),
                testResult = x.Elements("TestResult").Select(y => new {
                    markOne = (int)y.Element("MarkOne"),
                    markTwo = (int)y.Element("MarkTwo"),
                    slope = (int)y.Element("Slope")
                }).FirstOrDefault(),
                toneTestResult = x.Elements("ToneTestResult").Select(y => new {
                    totalTime = (int)y.Element("TotalTime"),
                    correctPecentage = (int)y.Element("CorrectPercentage")
                }).FirstOrDefault(),
                questionnaireResult = x.Elements("QuestionnaireResult").Elements("Question").Select(y => new {
                    question = (int)y.Attribute("Id"),
                    answer = (string)y.Descendants("Answer").FirstOrDefault().Attribute("Id")
                }).ToList(),
            }).FirstOrDefault();

        }
    }
}