使用属性过滤器读取 XDocument 的后代元素

Posted

技术标签:

【中文标题】使用属性过滤器读取 XDocument 的后代元素【英文标题】:Read descendant element of XDocument with attribute-filter 【发布时间】:2021-12-07 14:04:04 【问题描述】:

我将以下 XML 作为 XDocument 加载:

<?xml version="1.0" encoding="utf-8"?>
<europa3000_BASIC_DATA_CFG>
  <Version>5.0.6.6</Version>
  <Hash>555306</Hash>
  <GROUP Key="Basic_Data1" Pos="1">
    <Data Key="GeneralLedgerInterface" Pos="1">1</Data>
    <Data Key="CollectivePostings" Pos="2">2</Data>
    <Data Key="PostingDate" Pos="3">2</Data>
    <Data Key="PostSalesExpenseNet" Pos="4">1</Data>
    <Data Key="PostCreditNotesNeg" Pos="5">1</Data>
    <Data Key="PostingZeroAmounts" Pos="6">1</Data>
    <Data Key="BankDocumentNo" Pos="7">0</Data>
    <Data Key="AmountRoundingNC" Pos="15">2</Data>
    <Data Key="VATRoundingNC" Pos="17">2</Data>
    <Data Key="PurchasePriceCalcType" Pos="21">1</Data>
    <Data Key="PurchasePriceRounding" Pos="23">2</Data>
    <Data Key="DefaultVATCode" Pos="41">00</Data>
    <Data Key="DefaultInputTaxCode" Pos="42">00</Data>
    <DATA_LIST Key="FlatRateSalesTax" Pos="48">
      <List_Count>0</List_Count>
    </DATA_LIST>
  </GROUP>
  <GROUP Key="M003" Pos="2">
    <Data Key="MultipleWarehouses" Pos="1">0</Data>
    <Data Key="OwnWarehouse" Pos="2">1</Data>
    <Data Key="PassiveWarehous" Pos="6">0</Data>
  </GROUP>
</europa3000_BASIC_DATA_CFG>

现在我想获取具有特定键-属性-值的后代数据元素的值。我试过了

var fieldname = "DefaultVATCode";

var ele = xdc.Descendants("europa3000_BASIC_DATA_CFG").Where(x => (string) x.Attribute("Key") == "Basic_Data1").Where(x => (string) x.Attribute("Key") == fieldname).FirstOrDefault();

其中 xdc 是 XDocument。

但我没有电车。有人可以帮助我,我做错了什么吗?谢谢。

【问题讨论】:

【参考方案1】:

请尝试以下解决方案。

c#

void Main()

    XDocument xdoc = XDocument.Parse(@"<europa3000_BASIC_DATA_CFG>
        <Version>5.0.6.6</Version>
        <Hash>555306</Hash>
        <GROUP Key='Basic_Data1' Pos='1'>
            <Data Key='GeneralLedgerInterface' Pos='1'>1</Data>
            <Data Key='CollectivePostings' Pos='2'>2</Data>
            <Data Key='PostingDate' Pos='3'>2</Data>
            <Data Key='PostSalesExpenseNet' Pos='4'>1</Data>
            <Data Key='PostCreditNotesNeg' Pos='5'>1</Data>
            <Data Key='PostingZeroAmounts' Pos='6'>1</Data>
            <Data Key='BankDocumentNo' Pos='7'>0</Data>
            <Data Key='AmountRoundingNC' Pos='15'>2</Data>
            <Data Key='VATRoundingNC' Pos='17'>2</Data>
            <Data Key='PurchasePriceCalcType' Pos='21'>1</Data>
            <Data Key='PurchasePriceRounding' Pos='23'>2</Data>
            <Data Key='DefaultVATCode' Pos='41'>00</Data>
            <Data Key='DefaultInputTaxCode' Pos='42'>00</Data>
            <DATA_LIST Key='FlatRateSalesTax' Pos='48'>
                <List_Count>0</List_Count>
            </DATA_LIST>
        </GROUP>
        <GROUP Key='M003' Pos='2'>
            <Data Key='MultipleWarehouses' Pos='1'>0</Data>
            <Data Key='OwnWarehouse' Pos='2'>1</Data>
            <Data Key='PassiveWarehous' Pos='6'>0</Data>
        </GROUP>
    </europa3000_BASIC_DATA_CFG>");

    string fieldname = "DefaultVATCode";

    string pos = xdoc.Descendants("GROUP")
        .Where(x => x.Attribute("Key").Value.Equals("Basic_Data1"))
        .Elements("Data")
        .Where(x => x.Attribute("Key").Value.Equals(fieldname))
        .Attributes("Pos").FirstOrDefault().Value;

    Console.WriteLine("pos=0", pos);

输出

pos=41

【讨论】:

【参考方案2】:

我通常使用嵌套字典

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

namespace ConsoleApplication4

    class Program
    
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        
            XDocument doc = XDocument.Load(FILENAME);

            Dictionary<string, Dictionary<string, string>> dict = doc.Descendants("GROUP")
                .GroupBy(x => (string)x.Attribute("Key"), y => y.Elements("Data")
                    .GroupBy(a => (string)a.Attribute("Key"), b => (string)b)
                    .ToDictionary(a => a.Key, b => b.FirstOrDefault()))
                .ToDictionary(x => x.Key, y => y.FirstOrDefault());
        
    

【讨论】:

以上是关于使用属性过滤器读取 XDocument 的后代元素的主要内容,如果未能解决你的问题,请参考以下文章

C# XDocument 如何使用 linq 过滤元素

循环遍历 XDocument 的后代 - C#

使用 XDocument 和 Linq 读取 XML - 检查元素是不是为 NULL?

使用 XDocument 按属性查找元素

当我们有多个同名但属性不同的元素时,如何使用 Xdocument 从 xml 中删除一个元素

XDocument 读取具有名称空间的根元素的 XML 文件