Editing XML Output with LINQ

I have an XML output file from a running process that requires the content of various fields, edited to match a collection of tables in our database. For example, what's included in

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfUserReportPreviewListDto xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <UserReportPreviewListDto>
    <ExtensionData />
    <Id>previewReportFieldsId</Id>
    <Field0>-7</Field0>
    <Field1>L</Field1>
    <Field2>Lab Work Complete</Field2>
    <Field3>False</Field3>
    <Field4>LabWorkComplete</Field4>
    <Field6>False</Field6>
  </UserReportPreviewListDto>
  <UserReportPreviewListDto>
    <ExtensionData />
    <Id>previewReportFieldsId</Id>
    <Field0>-6</Field0>
    <Field1>S</Field1>
    <Field2>Sent to Lab</Field2>
    <Field3>False</Field3>
    <Field4>SentToLab</Field4>
    <Field6>False</Field6>
  </UserReportPreviewListDto>
  <UserReportPreviewListDto>
    <ExtensionData />
    <Id>previewReportFieldsId</Id>
    <Field0>-5</Field0>
    <Field1>V</Field1>
    <Field2>Void</Field2>
    <Field3>False</Field3>
    <Field4>Void</Field4>
    <Field6>True</Field6>
    <Field7>12/11/2013</Field7>
    <Field9>769</Field9>
  </UserReportPreviewListDto>

      

requires field 4 to change from LabWorkComplete (tblEnum.FieldTypeDesc) to 2 (tblEnum.FieldTypeNum).

I am very new to using LINQ and not even sure if this is the best way to do this. I created a DataSet in a project, with a DataTable populated from the database with what I need to work with. And ... that's as far as I know. I currently use a massive list of tedious If statements for this, and I think it might be more efficient than a collection of statements like this.

var xe = XElement.Load("serializer.xml");
string field4Value = xe.XPathSelectElement(@"/UserReportPreviewListDto/Field4").Value;
if (field4Value == "Incomplete")
{
    xe.XPathSelectElement(@"/UserReportPreviewListDto/Field4").Value = "0";
}
    else if (field4Value == "SendToLab")
{
xe.XPathSelectElement(@"/UserReportPreviewListDto/Field4").Value = "1";
}
    else if (field4Value == "LabWorkComplete")
{
    xe.XPathSelectElement(@"/UserReportPreviewListDto/Field4").Value = "2";
}

      

So where am I. If LINQ isn't the best way, what would be? If that were the case, what would be the best way to do it? In addition, any particularly useful resources in this direction that might be recommended could be appreciated; I would rather teach code than copy code. I hate to ask this again next week.

+3


source to share


2 answers


Your XML structure is weird. Field0...Field6

is not common, there are usually meaningful names. You can always write a function that encapsulates a string into an integer string conversion and just provide the xpath as an argument. Then go up and provide an xpath + conversion delegate and from now on it should be as easy as one line for each property. Here's an example implementation:

using System;
using System.Xml.Linq;
using System.Xml.XPath;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      var xe = XElement.Load("serializer.xml");
      ConvertValue(xe, @"/UserReportPreviewListDto/Field4", TranslateValueField4);
    }

    private static void ConvertValue(XElement xe, string xpath, TranslateValue translator)
    {
      string field4Value = xe.XPathSelectElement(xpath).Value;
      xe.XPathSelectElement(xpath).Value = translator(field4Value);
    }

    private delegate string TranslateValue(string value);

    private static string TranslateValueField4(string value)
    {
      switch (value)
      {
        case "Incomplete" :
          return "0";
        case "SendToLab" :
          return "1";
        case "LabWorkComplete":
          return "2";
        default:
          throw new NotImplementedException(); //or provide handling for unknown values
      }
    }
  }
}

      



You can also avoid using xpath and just repeat using foreach:

static void Main(string[] args)
{
  var doc = XDocument.Load(@"input.xml");
  foreach (var xe in doc.Root.Elements("UserReportPreviewListDto"))
  {
    ConvertValue(xe, "Field4", TranslateValueField4);
  }
  //doc.Save(path);
}

private static void ConvertValue(XElement xe, string fieldName, TranslateValue translator)
{
  //.Element returns Nothing if element is missing, may want to handle this case
  XElement field4 = xe.Element(fieldName);
  string field4Converted = TranslateValueField4(field4.Value);
  field4.SetValue(field4Converted);
}

      

+1


source


I am always, always, always prefect to store xml in custom classes and then work with them inside my C # environment. Makes the process of changing it more natural. Please take a look at my question here to see the best way to do this. It takes a little more time, but it ultimately makes things a lot easier. You said you want a better route and learn, didn't you?;)



0


source







All Articles