当数据集 WriteXml() 函数生成 xml 文件时,C# 如何使用 XDocument class 更新 xml 文件

C# How to update xml file using XDocument class when xml file generated by dataset WriteXml() function

我正在寻找一些指导如何用 XDocument 更新我复杂的 XML。 XML 看起来很复杂,因为它是从 DataSet.WriteXml()

生成的

这是我的 XML 首先由 QCSavedData.WriteXml(@strQCViewAllPath); QCSavedData 生成的数据集:

<?xml version="1.0" standalone="yes"?>
<HNNMY_ViewAll>
    <dgvViewAll_Vertical>
        <Section_x0020_>MS</Section_x0020_>
        <LineItem>Morgan Stanley</LineItem>
        <Revise_x0020_Date>10-09-2020</Revise_x0020_Date>
        <_x0032_010_x0020_FYA>126,966.0000</_x0032_010_x0020_FYA>
        <_x0032_011_x0020_FYA>128,810.0000</_x0032_011_x0020_FYA>
        <_x0032_012_x0020_FYA>140,948.0000</_x0032_012_x0020_FYA>
        <_x0032_013_x0020_FYA>150,090.0000</_x0032_013_x0020_FYA>
        <_x0031_Q_x0020_2014A>37,524.0000</_x0031_Q_x0020_2014A>
        <_x0032_Q_x0020_2014A>44,181.0000</_x0032_Q_x0020_2014A>
        <_x0033_Q_x0020_2014A>45,259.0000</_x0033_Q_x0020_2014A>
        <_x0034_Q_x0020_2014A>49,656.0000</_x0034_Q_x0020_2014A>
        <_x0032_014_x0020_FYA>176,620.0000</_x0032_014_x0020_FYA>
        <_x0031_Q_x0020_2015A>46,791.0000</_x0031_Q_x0020_2015A>
        <_x0032_Q_x0020_2015A>53,233.0000</_x0032_Q_x0020_2015A>
        <_x0033_Q_x0020_2015A>53,420.0000</_x0033_Q_x0020_2015A>
        <_x0034_Q_x0020_2015A>56,477.0000</_x0034_Q_x0020_2015A>
        <_x0032_015_x0020_FYA>209,921.0000</_x0032_015_x0020_FYA>
        <_x0031_Q_x0020_2016A>50,624.0000</_x0031_Q_x0020_2016A>
        <_x0032_Q_x0020_2016A>54,341.0000</_x0032_Q_x0020_2016A>
        <_x0033_Q_x0020_2016A>56,802.0000</_x0033_Q_x0020_2016A>
        <GroupKey>Consensus Model~Total Revenue Including VAT~RD_001~NBM~~1~MS</GroupKey>
    </dgvViewAll_Vertical>
</HNNMY_ViewAll>
  1. 看到这是<Section_x0020_>MS</Section_x0020_>当节是MS时如何查询因为节有x0020?

  2. 看这个 <_x0032_010_x0020_FYA>126,966.0000</_x0032_010_x0020_FYA> 数据表有很多列,如 2010 FYA、2011 FYA .... 2014A 第一季度,但是当数据表数据保存在 xml 中时,它会像这样显示 <_x0032_010_x0020_FYA>126,966.0000</_x0032_010_x0020_FYA> 然后我如何更新此标签内的值?

  3. 看到这个<GroupKey>Consensus Model~Total Revenue Including VAT~RD_001~NBM~~1~MS</GroupKey>

我必须这样查询

XDocumentSection == GroupKey.Split('~')[5] AND Column Name is 2010 FYA 然后更新 column 2010 FYA 中的值表示此列的值 <_x0032_010_x0020_FYA>126,966.0000</_x0032_010_x0020_FYA>

请帮助我提供示例代码,指导我如何更新 XML。

DataSet 写入 XML 时,输出显示在 DataTable.WriteXml() 的文档中。它看起来像:

<DataSetName>  
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <!--Schema information here, if you have requested it -->
  </xs:schema>  
  <!--The first table: -->
  <Table1Name>  <!--This repeats for every row in Table1 -->
    <!-- Column values -->
    <Column1Name>Value 1.1</Column1Name>  
    <Column2Name>Value 2.1</Column2Name>  
  </Table1Name>  
  <Table1Name> 
    <!-- Column values -->
    <Column1Name>Value 1.2</Column1Name>  
    <Column2Name>Value 2.2</Column2Name>  
  </Table1Name>  
  <!--The second table: -->
  <Table2Name>  <!--This repeats for every row in Table2 -->
    <!-- Column values -->
    <ColumnName>Value</ColumnName>  
  </Table2Name>  
  <!--And the remaining tables if any follow sequentially -->
</DataSetName>  

请注意,数据集、table 和列名称变为 XML 元素名称。但是,并不是每个字符串都可以用作格式正确的 XML 元素名称,这是由 XML standard 定义的。稍微简化一下,格式正确的元素名称必须:

  • 以 Unicode 字母或 _ 开头。
  • 随后由 Unicode 字母数字字符组成,_-.

因此 2010 FYA 不能是格式正确的 XML 元素名称,因为它以数字字符开头并包含空格。因此,在这种情况下,框架使用 XmlConvert.EncodeLocalName(String) 将任意字符串编码为格式正确的 XML 名称:

This method is similar to the EncodeName method except that it encodes the colon character, which guarantees that the name can be used as the local name part of a namespace qualified name.

以及相关的XmlConvert.EncodeName(String)

This method translates invalid characters, such as spaces or half-width Katakana, that need to be mapped to XML names without the support or presence of schemas. The invalid characters are translated into escaped numeric entity encodings.

The escape character is "_". Any XML name character that does not conform to the XML 1.0 spec (fourth edition) recommendation is escaped as xHHHH. The HHHH string stands for the four-digit hexadecimal UCS-2 code for the character in most significant bit first order. For example, the name Order Details is encoded as Order_x0020_Details.

The underscore character does not need to be escaped unless it is followed by a character sequence that together with the underscore can be misinterpreted as an escape sequence when decoding the name. For example, Order_Details is not encoded, but Order_x0020_ is encoded as Order_x005f_x0020_. No shortforms are allowed. For example, the forms x20 and __ are not generated.

如果要查询XML带有数据集,table或列名,必须调用XmlConvert.EncodeLocalName(name)来确定XML中使用的名称.反之,如果要查询从XML读取的某个元素名称的数据集,则必须调用XmlConvert.DecodeName(String)重新生成原始名称。

例如要更新某些 XDocument xdocument 中的 2010 FYA 列,您可以这样做:

var tableName = XmlConvert.EncodeLocalName("dgvViewAll_Vertical"); // EncodeLocalName is not strictly needed here since dgvViewAll_Vertical happens to be a well-formed XML name
var sectionName = XmlConvert.EncodeLocalName("Section ");
var groupKeyName = XmlConvert.EncodeLocalName("GroupKey"); // EncodeLocalName is not strictly needed here since GroupKey happens to be a well-formed XML name
var columnName = XmlConvert.EncodeLocalName("2010 FYA");

var columnValue = "New Value";

var ns = xdocument.Root.Name.Namespace;
var columns = xdocument.Root
    .Elements(ns + tableName)
    // Add error handling here when groupKeyName is not found or not in the expected syntax
    .Where(e => e.Element(ns + sectionName)?.Value == e.Element(ns + groupKeyName).Value.Split('~').Last()) 
    .Select(e => e.Element(ns + columnName));

foreach (var column in columns)
{
    column.Value = columnValue;
}

请注意,此代码假定您的 data set, data tables and data columns 都使用相同的 XML 命名空间(上面代码中的 ns)。您问题中显示的 XML 也是如此。如果不是这样,则在查询 table 和列名时需要使用适当的命名空间。

演示 fiddle here.