C#.NET 和解析来自服务器的 XML 响应
C#.NET and parsing XML response from server
我有多年使用 JS、Python 和 JSON 的经验,但在过去一周内才开始使用 C#.NET 和 XML。
我必须为 Quickbooks Desktop 编写一个解决方案,以将多个发票行项目合并为一个行项目。我从 Intuit 那里得到的例子有 10 年的历史了。从 SO 主题来看,我并不完全清楚我的用例的现代方法是什么:答案是 +6 年前的,或者它与从文件中读取有关——我正在尝试解析响应。
这是服务器响应的样子(我暂时将其写入文件),然后是一些问题:
<QBXML>
<QBXMLMsgsRs>
<InvoiceQueryRs requestID="0" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
<!-- RECORD 1 -->
<InvoiceRet>
<TxnID>3B58B-1540309911</TxnID>
<EditSequence>1540587328</EditSequence>
<TxnNumber>27058</TxnNumber>
<CustomerRef>
<ListID>800006FF-1540307596</ListID>
<FullName>Test Co.:Test 1</FullName>
</CustomerRef>
<RefNumber>L-9</RefNumber>
<Subtotal>2212.00</Subtotal>
<BalanceRemaining>2212.00</BalanceRemaining>
<IsPaid>false</IsPaid>
<!-- RECORD 1: INVOICE LINE ITEM 1 -->
<InvoiceLineRet>
<TxnLineID>3B58D-1540309911</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 1; TASK: Wrap-up</Desc>
<Quantity>6</Quantity>
<Rate>220</Rate>
<Amount>1320.00</Amount>
</InvoiceLineRet>
<!-- RECORD 1: INVOICE LINE ITEM 2 -->
<InvoiceLineRet>
<TxnLineID>3B58E-1540309911</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 1; TASK: Kickoff</Desc>
<Quantity>4</Quantity>
<Rate>220</Rate>
<Amount>880.00</Amount>
</InvoiceLineRet>
<!-- RECORD 1: INVOICE LINE ITEM 3 -->
<InvoiceLineRet>
<TxnLineID>3B58F-1540309911</TxnLineID>
<ItemRef>
<ListID>80000025-1538518495</ListID>
<FullName>Travel:Travel Meals</FullName>
</ItemRef>
<Desc>DATE: Oct 23, 2018; PROJECT: Test 1</Desc>
<Rate>12</Rate>
<Amount>12.00</Amount>
</InvoiceLineRet>
</InvoiceRet>
<!-- RECORD 2 -->
<InvoiceRet>
<TxnID>3B595-1540830324</TxnID>
<EditSequence>1540830324</EditSequence>
<TxnNumber>27060</TxnNumber>
<CustomerRef>
<ListID>80000700-1540307618</ListID>
<FullName>Test Co.:Test 2</FullName>
</CustomerRef>
<RefNumber>L-11</RefNumber>
<Subtotal>2760.00</Subtotal>
<BalanceRemaining>2760.00</BalanceRemaining>
<!-- RECORD 2: INVOICE LINE ITEM 1 -->
<InvoiceLineRet>
<TxnLineID>3B597-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Prebill Task</Desc>
<Rate>1000</Rate>
<Amount>1000.00</Amount>
</InvoiceLineRet>
<!-- RECORD 2: INVOICE LINE ITEM 2 -->
<InvoiceLineRet>
<TxnLineID>3B598-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Present Findings</Desc>
<Quantity>3</Quantity>
<Rate>0.00</Rate>
<Amount>0.00</Amount>
</InvoiceLineRet>
<!-- RECORD 2: INVOICE LINE ITEM 3 -->
<InvoiceLineRet>
<TxnLineID>3B599-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Research</Desc>
<Quantity>2</Quantity>
<Rate>220</Rate>
<Amount>440.00</Amount>
</InvoiceLineRet>
<!-- RECORD 2: INVOICE LINE ITEM 4 -->
<InvoiceLineRet>
<TxnLineID>3B59A-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Project Launch</Desc>
<Quantity>6</Quantity>
<Rate>220</Rate>
<Amount>1320.00</Amount>
</InvoiceLineRet>
</InvoiceRet>
</InvoiceQueryRs>
</QBXMLMsgsRs>
</QBXML>
- 一般来说,现代的解析方法是什么以便可以引用每个元素?
类似 xml.InvoiceRet[0].TxnId
的东西 3B58B-1540309911
。
- 鉴于父节点
<InvoiceRet>
是非描述性的,如何引用每条记录?您是否必须遍历每个 <InvoiceRet>
?
我从 Intuit 文档中尝试过的内容:
// this is where the query is sent to the QB and response is returned
var responseSet = sessionManager.DoRequests(requestSet);
// take the response and get the first element, I guess?
var response = responseSet.ResponseList.GetAt(0);
var customerRetList = response.Detail as ICustomerRetList;
// print the number of records
// it should be 2, but comes back with nothing
Console.WriteLine(customerRetList.Count);
对于我的用例来说,Basic Query (LINQ to XML) 似乎是最佳选择。决定使用以下方法解析对字符串的响应:
// Do the request and get the response message set object
var responseSet = sessionManager.DoRequests(requestSet);
// Convert response to string
var responseXml = responseSet.ToXMLString();
// Then the LINQ to XML for the string that I'm still working through
var xmlDoc = XDocument.Parse(responseXml);
// Set the xmlDoc root
var xmlDocRoot = xmlDoc.Root.Element("QBXMLMsgsRs")
.Element("InvoiceQueryRs")
.Elements("InvoiceRet");
// Iterate through the elements to get values and do some logic
foreach (var invoiceElement in xmlDocRoot)
{
var editSequence = (string) invoiceElement.Element("EditSequence");
}
我将结果放入数据表中,所以结果是平的。我从文件中得到结果。 Load 方法使用 URL 或文件名。如果您有字符串,请将 Load() 替换为 Parse()。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("TxnID", typeof(string));
dt.Columns.Add("EditSequence", typeof(string));
dt.Columns.Add("TxnNumber", typeof(string));
dt.Columns.Add("CustomerRef_ListID", typeof(string));
dt.Columns.Add("CustomerRef_FullName", typeof(string));
dt.Columns.Add("RefNumber", typeof(string));
dt.Columns.Add("Subtotal", typeof(decimal));
dt.Columns.Add("BalanceRemaining", typeof(decimal));
dt.Columns.Add("IsPaid", typeof(Boolean));
dt.Columns.Add("ItemRef_ListID", typeof(string));
dt.Columns.Add("ItemRef_FullName", typeof(string));
dt.Columns.Add("Desc", typeof(string));
dt.Columns.Add("Quantity", typeof(int));
dt.Columns.Add("Rate", typeof(decimal));
dt.Columns.Add("Amount", typeof(decimal));
XDocument doc = XDocument.Load(FILENAME);
foreach (XElement invoiceRet in doc.Descendants("InvoiceRet"))
{
string txnId = (string)invoiceRet.Element("TxnID");
string editSequence = (string)invoiceRet.Element("EditSequence");
string txnNumber = (string)invoiceRet.Element("TxnNumber");
XElement customerRef = invoiceRet.Element("CustomerRef");
string custListId = (string)customerRef.Element("ListID");
string custFullName = (string)customerRef.Element("FullName");
string refNumber = (string)invoiceRet.Element("RefNumber");
decimal subtotal = (decimal)invoiceRet.Element("Subtotal");
decimal balance = (decimal)invoiceRet.Element("BalanceRemaining");
Boolean? isPaid = (Boolean?)invoiceRet.Element("IsPaid");
foreach (XElement invoiceLine in invoiceRet.Elements("InvoiceLineRet"))
{
string lineListId = (string)invoiceLine.Descendants("ListID").FirstOrDefault();
string lineFullName = (string)invoiceLine.Descendants("FullName").FirstOrDefault();
string desc = (string)invoiceLine.Element("Desc");
int? quantity = (int?)invoiceLine.Element("Quantity");
decimal rate = (decimal)invoiceLine.Element("Rate");
decimal amount = (decimal)invoiceLine.Element("Amount");
dt.Rows.Add(new object[] {
txnId, editSequence, txnNumber, custListId, custFullName,
refNumber, subtotal, balance, isPaid,
lineListId, lineFullName, desc, quantity, rate, amount
});
}
}
}
}
}
我有多年使用 JS、Python 和 JSON 的经验,但在过去一周内才开始使用 C#.NET 和 XML。
我必须为 Quickbooks Desktop 编写一个解决方案,以将多个发票行项目合并为一个行项目。我从 Intuit 那里得到的例子有 10 年的历史了。从 SO 主题来看,我并不完全清楚我的用例的现代方法是什么:答案是 +6 年前的,或者它与从文件中读取有关——我正在尝试解析响应。
这是服务器响应的样子(我暂时将其写入文件),然后是一些问题:
<QBXML>
<QBXMLMsgsRs>
<InvoiceQueryRs requestID="0" statusCode="0" statusSeverity="Info" statusMessage="Status OK">
<!-- RECORD 1 -->
<InvoiceRet>
<TxnID>3B58B-1540309911</TxnID>
<EditSequence>1540587328</EditSequence>
<TxnNumber>27058</TxnNumber>
<CustomerRef>
<ListID>800006FF-1540307596</ListID>
<FullName>Test Co.:Test 1</FullName>
</CustomerRef>
<RefNumber>L-9</RefNumber>
<Subtotal>2212.00</Subtotal>
<BalanceRemaining>2212.00</BalanceRemaining>
<IsPaid>false</IsPaid>
<!-- RECORD 1: INVOICE LINE ITEM 1 -->
<InvoiceLineRet>
<TxnLineID>3B58D-1540309911</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 1; TASK: Wrap-up</Desc>
<Quantity>6</Quantity>
<Rate>220</Rate>
<Amount>1320.00</Amount>
</InvoiceLineRet>
<!-- RECORD 1: INVOICE LINE ITEM 2 -->
<InvoiceLineRet>
<TxnLineID>3B58E-1540309911</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 1; TASK: Kickoff</Desc>
<Quantity>4</Quantity>
<Rate>220</Rate>
<Amount>880.00</Amount>
</InvoiceLineRet>
<!-- RECORD 1: INVOICE LINE ITEM 3 -->
<InvoiceLineRet>
<TxnLineID>3B58F-1540309911</TxnLineID>
<ItemRef>
<ListID>80000025-1538518495</ListID>
<FullName>Travel:Travel Meals</FullName>
</ItemRef>
<Desc>DATE: Oct 23, 2018; PROJECT: Test 1</Desc>
<Rate>12</Rate>
<Amount>12.00</Amount>
</InvoiceLineRet>
</InvoiceRet>
<!-- RECORD 2 -->
<InvoiceRet>
<TxnID>3B595-1540830324</TxnID>
<EditSequence>1540830324</EditSequence>
<TxnNumber>27060</TxnNumber>
<CustomerRef>
<ListID>80000700-1540307618</ListID>
<FullName>Test Co.:Test 2</FullName>
</CustomerRef>
<RefNumber>L-11</RefNumber>
<Subtotal>2760.00</Subtotal>
<BalanceRemaining>2760.00</BalanceRemaining>
<!-- RECORD 2: INVOICE LINE ITEM 1 -->
<InvoiceLineRet>
<TxnLineID>3B597-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Prebill Task</Desc>
<Rate>1000</Rate>
<Amount>1000.00</Amount>
</InvoiceLineRet>
<!-- RECORD 2: INVOICE LINE ITEM 2 -->
<InvoiceLineRet>
<TxnLineID>3B598-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Present Findings</Desc>
<Quantity>3</Quantity>
<Rate>0.00</Rate>
<Amount>0.00</Amount>
</InvoiceLineRet>
<!-- RECORD 2: INVOICE LINE ITEM 3 -->
<InvoiceLineRet>
<TxnLineID>3B599-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Research</Desc>
<Quantity>2</Quantity>
<Rate>220</Rate>
<Amount>440.00</Amount>
</InvoiceLineRet>
<!-- RECORD 2: INVOICE LINE ITEM 4 -->
<InvoiceLineRet>
<TxnLineID>3B59A-1540830324</TxnLineID>
<ItemRef>
<ListID>80000002-1443563699</ListID>
<FullName>Consulting Fees</FullName>
</ItemRef>
<Desc>PROJECT: Test 2; TASK: Project Launch</Desc>
<Quantity>6</Quantity>
<Rate>220</Rate>
<Amount>1320.00</Amount>
</InvoiceLineRet>
</InvoiceRet>
</InvoiceQueryRs>
</QBXMLMsgsRs>
</QBXML>
- 一般来说,现代的解析方法是什么以便可以引用每个元素?
类似 xml.InvoiceRet[0].TxnId
的东西 3B58B-1540309911
。
- 鉴于父节点
<InvoiceRet>
是非描述性的,如何引用每条记录?您是否必须遍历每个<InvoiceRet>
?
我从 Intuit 文档中尝试过的内容:
// this is where the query is sent to the QB and response is returned
var responseSet = sessionManager.DoRequests(requestSet);
// take the response and get the first element, I guess?
var response = responseSet.ResponseList.GetAt(0);
var customerRetList = response.Detail as ICustomerRetList;
// print the number of records
// it should be 2, but comes back with nothing
Console.WriteLine(customerRetList.Count);
对于我的用例来说,Basic Query (LINQ to XML) 似乎是最佳选择。决定使用以下方法解析对字符串的响应:
// Do the request and get the response message set object
var responseSet = sessionManager.DoRequests(requestSet);
// Convert response to string
var responseXml = responseSet.ToXMLString();
// Then the LINQ to XML for the string that I'm still working through
var xmlDoc = XDocument.Parse(responseXml);
// Set the xmlDoc root
var xmlDocRoot = xmlDoc.Root.Element("QBXMLMsgsRs")
.Element("InvoiceQueryRs")
.Elements("InvoiceRet");
// Iterate through the elements to get values and do some logic
foreach (var invoiceElement in xmlDocRoot)
{
var editSequence = (string) invoiceElement.Element("EditSequence");
}
我将结果放入数据表中,所以结果是平的。我从文件中得到结果。 Load 方法使用 URL 或文件名。如果您有字符串,请将 Load() 替换为 Parse()。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("TxnID", typeof(string));
dt.Columns.Add("EditSequence", typeof(string));
dt.Columns.Add("TxnNumber", typeof(string));
dt.Columns.Add("CustomerRef_ListID", typeof(string));
dt.Columns.Add("CustomerRef_FullName", typeof(string));
dt.Columns.Add("RefNumber", typeof(string));
dt.Columns.Add("Subtotal", typeof(decimal));
dt.Columns.Add("BalanceRemaining", typeof(decimal));
dt.Columns.Add("IsPaid", typeof(Boolean));
dt.Columns.Add("ItemRef_ListID", typeof(string));
dt.Columns.Add("ItemRef_FullName", typeof(string));
dt.Columns.Add("Desc", typeof(string));
dt.Columns.Add("Quantity", typeof(int));
dt.Columns.Add("Rate", typeof(decimal));
dt.Columns.Add("Amount", typeof(decimal));
XDocument doc = XDocument.Load(FILENAME);
foreach (XElement invoiceRet in doc.Descendants("InvoiceRet"))
{
string txnId = (string)invoiceRet.Element("TxnID");
string editSequence = (string)invoiceRet.Element("EditSequence");
string txnNumber = (string)invoiceRet.Element("TxnNumber");
XElement customerRef = invoiceRet.Element("CustomerRef");
string custListId = (string)customerRef.Element("ListID");
string custFullName = (string)customerRef.Element("FullName");
string refNumber = (string)invoiceRet.Element("RefNumber");
decimal subtotal = (decimal)invoiceRet.Element("Subtotal");
decimal balance = (decimal)invoiceRet.Element("BalanceRemaining");
Boolean? isPaid = (Boolean?)invoiceRet.Element("IsPaid");
foreach (XElement invoiceLine in invoiceRet.Elements("InvoiceLineRet"))
{
string lineListId = (string)invoiceLine.Descendants("ListID").FirstOrDefault();
string lineFullName = (string)invoiceLine.Descendants("FullName").FirstOrDefault();
string desc = (string)invoiceLine.Element("Desc");
int? quantity = (int?)invoiceLine.Element("Quantity");
decimal rate = (decimal)invoiceLine.Element("Rate");
decimal amount = (decimal)invoiceLine.Element("Amount");
dt.Rows.Add(new object[] {
txnId, editSequence, txnNumber, custListId, custFullName,
refNumber, subtotal, balance, isPaid,
lineListId, lineFullName, desc, quantity, rate, amount
});
}
}
}
}
}