【问题标题】:Editing XML Output With LINQ使用 LINQ 编辑 XML 输出
【发布时间】:2015-02-03 22:09:20
【问题描述】:

我有一个来自正在运行的进程的 XML 输出文件,该文件需要根据我们数据库中的表集合编辑各种字段的内容。例如,包含在中的内容

<?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>

需要将 Field4 从 LabWorkComplete (tblEnum.FieldTypeDesc) 更改为 2 (tblEnum.FieldTypeNum)。

我对使用 LINQ 非常陌生,甚至不能完全确定它是否是最好的方法。我在项目中创建了一个 DataSet,其中一个 DataTable 从数据库中填充了我需要使用的内容。而且……就我所知。现在我正在使用大量繁琐的 If 语句来完成此任务,并且我认为这种方法可能比这样的语句集合更有效。

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";
}

这就是我所在的地方。如果 LINQ 不是最好的途径,那会是什么?如果是的话,最好的方法是什么?此外,任何可以推荐的沿着这些思路的特别有用的资源将不胜感激;我更愿意学习代码而不是复制代码。毕竟,我不想下周再问这个问题。

【问题讨论】:

    标签: c# sql xml linq


    【解决方案1】:

    您的 XML 结构很奇怪。 Field0...Field6 并不常见,其中通常有有意义的名称。您始终可以编写一个封装字符串到整数字符串转换的函数,并且只需提供一个 xpath 作为参数。然后再上一层,提供 xpath + 转换委托,从这一点开始,它就像每个属性一行一样简单。下面是一个实现示例:

    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
          }
        }
      }
    }
    

    您也可以避免使用 xpath,而只需使用 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);
    }
    

    【讨论】:

    • 这很奇怪,是的。但它是客户提供给我们的,所以你能做什么,嗯?你有你建议的代码示例吗?我想它并不像听起来那么复杂,但看到它写出来将是一个巨大的帮助。
    • 是否有一个可行的 foreach 语句可用于 XML 文件中的多条记录,放置在 xe 的声明下方以循环通过 ConvertValue 调用?有什么理由我不需要包含一个吗?
    • @Eiketsu:当然,这不是问题,但首先我可以要求您在 XML 文件中添加更多项目(编辑您的问题)吗?只是想确保我理解了这个问题。
    • @Eiketsu:我们暂时不要将数据库纳入范围,直到其余部分都清楚为止。
    • 哈!看起来它做到了。它确实给了我一些新的学习内容。不止几个。唷。但这也是我将继续努力的一个很好的开始。非常感谢您的时间和帮助。非常感谢!!
    【解决方案2】:

    我总是,总是,总是将 xml 存储到自定义类中,然后在我的 C# 环境中使用它们。使修改它的过程感觉更加自然。请查看我的问题here 以了解执行此操作的最佳方法。这需要更多时间,但从长远来看,它会让事情变得容易得多。你说你想要最好的路线和学习,对吧? ;)

    【讨论】:

    • 这种方法永远、永远、永远不会在企业环境中奏效。 :) 在某些时候,您将需要对所有序列化进行手动处理。特别是如果序列化逻辑中有分支,即如果是this,那么field5是一个整数,并且存储在propertyX中,否则如果field6是一个日期,那么propertyY等。更糟糕的是如果处理依赖于其他字段,即如果field5是this,那么field6 是磁盘上的路径,所以你需要打开一个文件,如果 field5 是那个,而 field6 是 FTP 上的路径,你需要 field7 和 field8 的凭据。
    • 这是一个很好的方法,Volearix,我很欣赏这个建议,但@Neolisk 提出了一个很好的观点。这最终将需要根据该程序将运行的报告的主表进一步改变事情。因此,我目前正在处理的领域(“类型”)中的 Field4 可能在下一份报告中有所不同(例如,“CreationDate”)。因此,这将增加另一个级别的复杂性,您的系统似乎可能难以处理(如果我理解正确的话)。这是我认为 LINQ 可能是可行的方法的另一个原因,但仍不确定。
    猜你喜欢
    • 1970-01-01
    • 2017-01-11
    • 2015-04-01
    • 1970-01-01
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多