从 C# 中的大 xml 读取子节点值

Posted

技术标签:

【中文标题】从 C# 中的大 xml 读取子节点值【英文标题】:Reading a child node value from a big xml in C# 【发布时间】:2020-09-12 06:03:37 【问题描述】:

我有来自服务的 4000 行 xmlresponse。我使用所需的标签名称从那个大 xml 中提取了特定部分

XmlNodeList xmlForms = xmlDoc.GetElementsByTagName("Form");

从此节点示例部分 xml 如下所示

 <Form>
  <FormID>3434294</FormID>
  <StatusDate>0001-01-01T00:00:00</StatusDate>
  <InternalFormNo>CADFADSFSAGDSADG01</InternalFormNo>
  <ExternalFormNo>CADFASDFASFSC1001</ExternalFormNo>
  <ProposalDescription>Treatment</ProposalDescription>
  <ProposalForm>false</ProposalForm>
  <StateApprovals>
    <StateApproval>
      <StateApprovalID>2245363363636</StateApprovalID>
      <IssueLimitSet>
        <IssueLimitSetID>88</IssueLimitSetID>
        <Name>AccAdv</Name>
        <Note />
        <ModifyDate>0001-01-01T00:00:00</ModifyDate>
        <IssueLimits>
          <IssueLimit>
            <IssueLimtID>80</IssueLimtID>
            <GIAmount>62</GIAmount>
            <SIAmount>0.00</SIAmount>
            <ChangeProcessingCGIAmount>0</ChangeProcessingCGIAmount>
            <MaximumMultiSelect>0</MaximumMultiSelect>
            <CreateDate>0001-01-01T00:00:00</CreateDate>
            <ModifyDate>0001-01-01T00:00:00</ModifyDate>
          </IssueLimit>
        </IssueLimits>
      </IssueLimitSet>
      <SpecialProcessing>false</SpecialProcessing>
      <ModifyUser>TESTUSER</ModifyUser>
      <ModifyDate>2016-02-17T17:52:59.163</ModifyDate>
    </StateApproval>
  </StateApprovals>
</Form>

我需要读取节点 GIAmount 并提取它的值 (62)。但是 xpath 表示法总是给我空值。如何从此子 xml 中读取此子节点。简单的 xpath 也总是给出 null 。

foreach (XmlNode form in xmlForms)
                        
                            var statusDate= form.SelectSingleNode("/Form/StatusDate"); //This always null i am getting


----------------原始xml------------在Variations->Forms->Form下 --在某些情况下,出现多个表单标签,我需要读取每个表单中的特定节点-------

<?xml version="1.0" encoding="utf-8"?>
<Product xmlns="http://testtest.com/twmku">
  <ProductID>72</ProductID>
  <InternalDescription>AccidentAdvance</InternalDescription>
  <ExternalDescription>AccidentAdvance</ExternalDescription>
  <Variations>
    <Variation>
      <VariationID>231</VariationID>
      <InternalDescription>AccidentAdvance123</InternalDescription>
      <ExternalDescription>AccidentAdvance</ExternalDescription>
      <ProposalDescription />
      <IsProposalReady>false</IsProposalReady>      
      <StatusDate>2009-03-26T00:00:00</StatusDate>
      <EffectiveDate>2009-04-01T00:00:00</EffectiveDate>
      <WithdrawnDate>0001-01-01T00:00:00</WithdrawnDate>
      <ModifyUser>Utesruser</ModifyUser>
      <ModifyDate>2011-11-30T10:35:26.313</ModifyDate>
      <Employers />
      <Forms>
        <Form>
          <FormID>3493</FormID>        
          <IsGeneric>true</IsGeneric>
          <HasLimitsInUnits>true</HasLimitsInUnits>
          <Description>AccAdv Master Policy</Description>
          <CreateUser>US\testMW</CreateUser>
          <CreateDate>0001-01-01T00:00:00</CreateDate>
          <ModifyUser>US\testMW</ModifyUser>
          <ModifyDate>2011-12-12T11:42:40.06</ModifyDate>          
          <DataElements />
          <StateApprovals>
            <StateApproval>
              <StateApprovalID>2256556</StateApprovalID> 
              <IssueLimitSet>
                <IssueLimitSetID>88</IssueLimitSetID>
                <Name>AccAdv Modtest</Name>
                <Note />
                <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                <IssueLimits>
                  <IssueLimit>
                    <IssueLimtID>80</IssueLimtID>
                    <Keyword>AccAdv Mod 1</Keyword>
                    <MinMarketingLimit>0.50</MinMarketingLimit>
                    <MaxMarketingLimit>12.00</MaxMarketingLimit>
                    <CGIAmount>0.00</CGIAmount>
                    <GIAmount>6</GIAmount>
                    <SIAmount>0.00</SIAmount>
                    <ChangeProcessingCGIAmount>0</ChangeProcessingCGIAmount>                   
                    <CreateDate>0001-01-01T00:00:00</CreateDate>
                    <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                  </IssueLimit>
                </IssueLimits>
              </IssueLimitSet>
              <StateRequirementSet />
              <QuestionSet />
              <SICSet />
              <DateFiled>0001-01-01T00:00:00</DateFiled>          
              <SpecialProcessing>false</SpecialProcessing>
              <ModifyUser>JBtestD</ModifyUser>
              <ModifyDate>2016-02-18T14:39:50.927</ModifyDate>
            </StateApproval>
          </StateApprovals>
          <Parameters />
          <IsSelected>true</IsSelected>
        </Form>

        <Form>
          <FormID>3495</FormID>
          <IsGeneric>true</IsGeneric>
          <HasLimitsInUnits>true</HasLimitsInUnits>
          <Description>AccAdv Master main</Description>
          <CreateUser>US\testMqW</CreateUser>
          <CreateDate>0001-01-01T00:00:00</CreateDate>
          <ModifyUser>US\testMW</ModifyUser>
          <ModifyDate>2011-12-12T11:42:40.06</ModifyDate>
          <DataElements />
          <StateApprovals>
            <StateApproval>
              <StateApprovalID>26556</StateApprovalID>
              <IssueLimitSet>
                <IssueLimitSetID>88</IssueLimitSetID>
                <Name>AccAdv Moretest</Name>
                <Note />
                <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                <IssueLimits>
                  <IssueLimit>
                    <IssueLimtID>84</IssueLimtID>
                    <Keyword>AccAdv Mod 1</Keyword>
                    <MinMarketingLimit>0.50</MinMarketingLimit>
                    <MaxMarketingLimit>12.00</MaxMarketingLimit>
                    <CGIAmount>0.00</CGIAmount>
                    <GIAmount>34</GIAmount>
                    <SIAmount>0.00</SIAmount>
                    <ChangeProcessingCGIAmount>0</ChangeProcessingCGIAmount>
                    <CreateDate>0001-01-01T00:00:00</CreateDate>
                    <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                  </IssueLimit>
                </IssueLimits>
              </IssueLimitSet>
              <StateRequirementSet />
              <QuestionSet />
              <SICSet />
              <DateFiled>0001-01-01T00:00:00</DateFiled>
              <SpecialProcessing>false</SpecialProcessing>
              <ModifyUser>JBtestD</ModifyUser>
              <ModifyDate>2016-02-18T14:39:50.927</ModifyDate>
            </StateApproval>
          </StateApprovals>
          <Parameters />
          <IsSelected>true</IsSelected>
        </Form>
      </Forms>      
      <ParameterValueSets />
      <AllowCustomRates>false</AllowCustomRates>
    </Variation>
  </Variations>
</Product>

【问题讨论】:

【参考方案1】:

您已经以Form 元素为目标,因此没有理由将它包含在XPath 中。只需跳过该标记,并使用其后代组成路径。

在你的情况下:"StateApprovals/StateApproval/IssueLimitSet/IssueLimits/GIAmount"

或者,更简洁:"//GIAmount"

请注意,我的回答是基于您帖子的片段,路径可能会根据实际内容发生变化。

【讨论】:

我尝试了所有选项仍然为空。当我观察到我的 xml 不必要的 xmlns 命名空间被随机添加时。我不确定为什么 xpath 表达式对我不起作用,在我读的一篇文章中,因为 xmlns xpath 不起作用,我们需要删除。但如果它在一个地方我们可以删除,甚至尝试使用正则表达式删除仍然总是给出 null。【参考方案2】:

最好使用LINQ to XML。使用它的方法,很容易获得任何 XML 元素。

(1) 您的 XML 具有默认命名空间。需要考虑到这一点。 (2) 多个&lt;Form&gt;...&lt;/Form&gt; 元素需要一个循环。

c#

void Main()

    XElement xelem = XElement.Parse(@"<Product xmlns='http://testtest.com/twmku'>
  <ProductID>72</ProductID>
  <InternalDescription>AccidentAdvance</InternalDescription>
  <ExternalDescription>AccidentAdvance</ExternalDescription>
  <Variations>
    <Variation>
      <VariationID>231</VariationID>
      <InternalDescription>AccidentAdvance123</InternalDescription>
      <ExternalDescription>AccidentAdvance</ExternalDescription>
      <ProposalDescription />
      <IsProposalReady>false</IsProposalReady>      
      <StatusDate>2009-03-26T00:00:00</StatusDate>
      <EffectiveDate>2009-04-01T00:00:00</EffectiveDate>
      <WithdrawnDate>0001-01-01T00:00:00</WithdrawnDate>
      <ModifyUser>Utesruser</ModifyUser>
      <ModifyDate>2011-11-30T10:35:26.313</ModifyDate>
      <Employers />
      <Forms>
        <Form>
          <FormID>3493</FormID>        
          <IsGeneric>true</IsGeneric>
          <HasLimitsInUnits>true</HasLimitsInUnits>
          <Description>AccAdv Master Policy</Description>
          <CreateUser>US\testMW</CreateUser>
          <CreateDate>0001-01-01T00:00:00</CreateDate>
          <ModifyUser>US\testMW</ModifyUser>
          <ModifyDate>2011-12-12T11:42:40.06</ModifyDate>          
          <DataElements />
          <StateApprovals>
            <StateApproval>
              <StateApprovalID>2256556</StateApprovalID> 
              <IssueLimitSet>
                <IssueLimitSetID>88</IssueLimitSetID>
                <Name>AccAdv Modtest</Name>
                <Note />
                <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                <IssueLimits>
                  <IssueLimit>
                    <IssueLimtID>80</IssueLimtID>
                    <Keyword>AccAdv Mod 1</Keyword>
                    <MinMarketingLimit>0.50</MinMarketingLimit>
                    <MaxMarketingLimit>12.00</MaxMarketingLimit>
                    <CGIAmount>0.00</CGIAmount>
                    <GIAmount>6</GIAmount>
                    <SIAmount>0.00</SIAmount>
                    <ChangeProcessingCGIAmount>0</ChangeProcessingCGIAmount>                   
                    <CreateDate>0001-01-01T00:00:00</CreateDate>
                    <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                  </IssueLimit>
                </IssueLimits>
              </IssueLimitSet>
              <StateRequirementSet />
              <QuestionSet />
              <SICSet />
              <DateFiled>0001-01-01T00:00:00</DateFiled>          
              <SpecialProcessing>false</SpecialProcessing>
              <ModifyUser>JBtestD</ModifyUser>
              <ModifyDate>2016-02-18T14:39:50.927</ModifyDate>
            </StateApproval>
          </StateApprovals>
          <Parameters />
          <IsSelected>true</IsSelected>
        </Form>
        <Form>
          <FormID>3495</FormID>
          <IsGeneric>true</IsGeneric>
          <HasLimitsInUnits>true</HasLimitsInUnits>
          <Description>AccAdv Master main</Description>
          <CreateUser>US\testMqW</CreateUser>
          <CreateDate>0001-01-01T00:00:00</CreateDate>
          <ModifyUser>US\testMW</ModifyUser>
          <ModifyDate>2011-12-12T11:42:40.06</ModifyDate>
          <DataElements />
          <StateApprovals>
            <StateApproval>
              <StateApprovalID>26556</StateApprovalID>
              <IssueLimitSet>
                <IssueLimitSetID>88</IssueLimitSetID>
                <Name>AccAdv Moretest</Name>
                <Note />
                <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                <IssueLimits>
                  <IssueLimit>
                    <IssueLimtID>84</IssueLimtID>
                    <Keyword>AccAdv Mod 1</Keyword>
                    <MinMarketingLimit>0.50</MinMarketingLimit>
                    <MaxMarketingLimit>12.00</MaxMarketingLimit>
                    <CGIAmount>0.00</CGIAmount>
                    <GIAmount>34</GIAmount>
                    <SIAmount>0.00</SIAmount>
                    <ChangeProcessingCGIAmount>0</ChangeProcessingCGIAmount>
                    <CreateDate>0001-01-01T00:00:00</CreateDate>
                    <ModifyDate>0001-01-01T00:00:00</ModifyDate>
                  </IssueLimit>
                </IssueLimits>
              </IssueLimitSet>
              <StateRequirementSet />
              <QuestionSet />
              <SICSet />
              <DateFiled>0001-01-01T00:00:00</DateFiled>
              <SpecialProcessing>false</SpecialProcessing>
              <ModifyUser>JBtestD</ModifyUser>
              <ModifyDate>2016-02-18T14:39:50.927</ModifyDate>
            </StateApproval>
          </StateApprovals>
          <Parameters />
          <IsSelected>true</IsSelected>
        </Form>
      </Forms>      
      <ParameterValueSets />
      <AllowCustomRates>false</AllowCustomRates>
    </Variation>
  </Variations>
</Product>");

    //string GIAmount = GIAmount.Descendants(ns + "GIAmount").FirstOrDefault().Value;
    XNamespace ns = xelem.GetDefaultNamespace();

    foreach (var el in xelem.Descendants(ns + "GIAmount"))
    
        Console.WriteLine("GIAmount=0", el.Value);    
    

输出

GIAmount=6
GIAmount=34

【讨论】:

感谢您的回复。您在独立应用程序中工作的示例。当我尝试合并到实际应用程序中时,我得到了 System.Xml.XmlException 异常:'根级别的数据无效。第 1 行,位置 1。当我检查我的表单变量时,添加了不必要的命名空间,但原来它不存在。比如 这些 xmlns 标签被添加了。 @San,请用现实生活中的 XML、命名空间等更新您的原始帖子。我会相应地更新我的答案。 我已经更新了 xml,你现在可以检查一下。在原始响应中,我将只有一个 xmlns 标记,每个 xml 文档都将具有该标记。一旦我执行 XmlNodeList xmlForms = xmlDoc.GetElementsByTagName("Form");我得到的所有表单标签。如果我尝试编写 xpath 表达式,则它不起作用。它总是返回 null。将其解析为 xelemt 它给出了上述异常 我只在解析时遇到问题。在遍历每个表单时,我试图解析表单内容,以便提取所需的值。 XmlNodeList xmlForms = xmlDoc.GetElementsByTagName("Form"); foreach (xmlForms 中的 XmlNode 表单) XElement ele = XElement.Parse(form.ToString()); @San,我的回答中缺少什么?我展示了如何检索所有 GIAmount 值。【参考方案3】:

一个值通常是不够的信息。试试下面的 xml linq:

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

namespace ConsoleApplication1

    class Program
    
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        
            string xml = File.ReadAllText(FILENAME);
            XDocument doc = XDocument.Parse(xml);
            XNamespace ns = doc.Root.GetDefaultNamespace();

            List<StateApproval> approvals = doc.Descendants(ns + "StateApproval").Select(x => new StateApproval()
            
                id = (string)x.Element(ns + "StateApprovalID"),
                limitSetId = (string)x.Descendants(ns + "IssueLimitSetID").FirstOrDefault(),
                name = (string)x.Descendants(ns + "Name").FirstOrDefault(),
                modifyDate = (DateTime)x.Descendants(ns + "ModifyDate").FirstOrDefault(),
                issueLimitId = (string)x.Descendants(ns + "IssueLimtID").FirstOrDefault(),
                giAmount = (decimal)x.Descendants(ns + "GIAmount").FirstOrDefault(),
                siAmount = (decimal)x.Descendants(ns + "SIAmount").FirstOrDefault(),
                changeAmount = (decimal)x.Descendants(ns + "ChangeProcessingCGIAmount").FirstOrDefault(),
                min = (decimal)x.Descendants(ns + "MinMarketingLimit").FirstOrDefault(),
                max = (decimal)x.Descendants(ns + "MaxMarketingLimit").FirstOrDefault(),
                createDate = (DateTime)x.Descendants(ns + "CreateDate").FirstOrDefault(),
            ).ToList();
        
    
    public class StateApproval
    
        public string id  get; set; 
        public string limitSetId  get; set; 
        public string name  get; set; 
        public DateTime modifyDate  get; set; 
        public string issueLimitId  get; set; 
        public decimal giAmount  get; set; 
        public decimal siAmount  get; set; 
        public decimal changeAmount  get; set; 
        public decimal min  get; set; 
        public decimal max  get; set; 
        public DateTime createDate  get; set; 

    

【讨论】:

我没有提供加载功能的 uri 路径。我的 xml 的运行时子集存在。它也没有转换为字符串。无法尝试您的选项。 用于字符串:XDocument doc = XDocument.Parse(string); 是的,我试过了。这。但对我来说,在解析 xmlexception 根级别的数据时异常给出 line1 位置 1 无效。当我观察到我的 xml 获得不必要的命名空间时。为此,我无法继续进行。 :(

以上是关于从 C# 中的大 xml 读取子节点值的主要内容,如果未能解决你的问题,请参考以下文章

c#读取XML多级子节点

通过c#读取xml的多个子节点

C#读取xml

在c#的winform 下怎么读取 xml文件中的数据?

C#判断xml节点下是不是有子节点

无法使用 c# 从 xml 读取值/节点