I have trouble to deserialize part of invoice XML.
Tag cac:InvoiceLine is repeating.
I need help to make list/array for element InvoiceLine and do foreach loop and extract values from child elements.
This is example of XML file
<?xml version="1.0" encoding="utf-8"?>
<env:DocumentEnvelope xmlns:env="urn:eFaktura:MinFinrs:envelop:schema">
<env:DocumentHeader>
<env:SalesInvoiceId>4372797</env:SalesInvoiceId>
<env:PurchaseInvoiceId>3935145</env:PurchaseInvoiceId>
<env:DocumentId>3ff1e4d7-9025-4908-b05b-26094758bd7d</env:DocumentId>
<env:CreationDate>2022-10-06</env:CreationDate>
<env:SendingDate>2022-10-06</env:SendingDate>
<env:DocumentPdf mimeCode="application/pdf"></env:DocumentPdf>
</env:DocumentHeader>
<env:DocumentBody>
<Invoice xmlns:cec="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"
xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:sbt="http://mfin.gov.rs/srbdt/srbdtext"
xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:mfin.gov.rs:srbdt:2022#conformant#urn:mfin.gov.rs:srbdtext:2022</cbc:CustomizationID>
<cbc:ID>24</cbc:ID>
<cbc:IssueDate>2022-10-06</cbc:IssueDate>
<cbc:DueDate>2022-10-20</cbc:DueDate>
<cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
<cbc:Note>PROD</cbc:Note>
<cbc:DocumentCurrencyCode>RSD</cbc:DocumentCurrencyCode>
<cac:InvoicePeriod>
<cbc:StartDate>2022-09-01</cbc:StartDate>
<cbc:EndDate>2022-09-30</cbc:EndDate>
<cbc:DescriptionCode>35</cbc:DescriptionCode>
</cac:InvoicePeriod>
<cac:AdditionalDocumentReference>
<cbc:ID>24</cbc:ID>
<cbc:DocumentType>PRILOG 1</cbc:DocumentType>
<cac:Attachment>
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" encodingCode="base64" filename="24.pdf"></cbc:EmbeddedDocumentBinaryObject>
</cac:Attachment>
</cac:AdditionalDocumentReference>
<cac:AccountingSupplierParty>
<cac:Party>
<cbc:EndpointID schemeID="9948">123456789</cbc:EndpointID>
<cac:PartyIdentification>
<cbc:ID>81906</cbc:ID>
</cac:PartyIdentification>
<cac:PartyName>
<cbc:Name>SUPPLIER NAME</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>SUPPLIER STREET</cbc:StreetName>
<cbc:CityName>SUPPLIER TOWN</cbc:CityName>
<cbc:PostalZone>SUPPLIER ZIP CODE</cbc:PostalZone>
<cac:AddressLine>
<cbc:Line>STREET,TOWN, ZIP</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>RS</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>RS123456789</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>SUPPLIER NAME</cbc:RegistrationName>
<cbc:CompanyID>98765432</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:ElectronicMail>[email protected]</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingSupplierParty>
<cac:AccountingCustomerParty>
<cac:Party>
<cbc:EndpointID schemeID="9948">111111111</cbc:EndpointID>
<cac:PartyIdentification />
<cac:PartyName>
<cbc:Name>CUSTOMER NAME</cbc:Name>
</cac:PartyName>
<cac:PostalAddress>
<cbc:StreetName>CUSTOMER street</cbc:StreetName>
<cbc:CityName>CUSTOMER town</cbc:CityName>
<cbc:PostalZone>CUSTOMER zip</cbc:PostalZone>
<cac:AddressLine>
<cbc:Line>street, town, zip</cbc:Line>
</cac:AddressLine>
<cac:Country>
<cbc:IdentificationCode>RS</cbc:IdentificationCode>
</cac:Country>
</cac:PostalAddress>
<cac:PartyTaxScheme>
<cbc:CompanyID>RS111111111</cbc:CompanyID>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:PartyTaxScheme>
<cac:PartyLegalEntity>
<cbc:RegistrationName>CUSTOMER NAME</cbc:RegistrationName>
<cbc:CompanyID>22222222</cbc:CompanyID>
</cac:PartyLegalEntity>
<cac:Contact>
<cbc:ElectronicMail>[email protected]</cbc:ElectronicMail>
</cac:Contact>
</cac:Party>
</cac:AccountingCustomerParty>
<cac:Delivery>
<cbc:ActualDeliveryDate>2022-09-30</cbc:ActualDeliveryDate>
</cac:Delivery>
<cac:PaymentMeans>
<cbc:PaymentMeansCode>30</cbc:PaymentMeansCode>
<cbc:PaymentID>223985-2209</cbc:PaymentID>
<cac:PayeeFinancialAccount>
<cbc:ID>100-000000-11</cbc:ID>
</cac:PayeeFinancialAccount>
</cac:PaymentMeans>
<cac:TaxTotal>
<cbc:TaxAmount currencyID="RSD">967.2</cbc:TaxAmount>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="RSD">9464</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="RSD">946.4</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>10</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
<cac:TaxSubtotal>
<cbc:TaxableAmount currencyID="RSD">104</cbc:TaxableAmount>
<cbc:TaxAmount currencyID="RSD">20.8</cbc:TaxAmount>
<cac:TaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>20</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:TaxCategory>
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount currencyID="RSD">9568</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount currencyID="RSD">9568</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount currencyID="RSD">10535.2</cbc:TaxInclusiveAmount>
<cbc:AllowanceTotalAmount currencyID="RSD">0</cbc:AllowanceTotalAmount>
<cbc:PrepaidAmount currencyID="RSD">0</cbc:PrepaidAmount>
<cbc:PayableAmount currencyID="RSD">10535.2</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine>
<cbc:ID>1</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTQ">65</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="RSD">3971.5</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>line 1 description</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>1</cbc:ID>
</cac:SellersItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>10</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="RSD">61.1</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTQ">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
<cac:InvoiceLine>
<cbc:ID>2</cbc:ID>
<cbc:InvoicedQuantity unitCode="MTQ">65</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount currencyID="RSD">2535</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Name>line 2 description</cbc:Name>
<cac:SellersItemIdentification>
<cbc:ID>3</cbc:ID>
</cac:SellersItemIdentification>
<cac:ClassifiedTaxCategory>
<cbc:ID>S</cbc:ID>
<cbc:Percent>10</cbc:Percent>
<cac:TaxScheme>
<cbc:ID>VAT</cbc:ID>
</cac:TaxScheme>
</cac:ClassifiedTaxCategory>
</cac:Item>
<cac:Price>
<cbc:PriceAmount currencyID="RSD">39</cbc:PriceAmount>
<cbc:BaseQuantity unitCode="MTQ">1</cbc:BaseQuantity>
</cac:Price>
</cac:InvoiceLine>
</Invoice>
</env:DocumentBody>
</env:DocumentEnvelope>
I generated classes in Visual Studio
1 Copy XML data to the clipboard
2 In VS, Edit > Paste Special > "Paste Xml as classes"
This is my code for get all other values from xml.
static void Main(string[] args)
{
XmlSerializer serializer =
new XmlSerializer(typeof(XmlStr.DocumentEnvelope));
// Declare an object variable of the type to be deserialized.
XmlStr.DocumentEnvelope envelope;
using (Stream reader = new FileStream(@"C:\\Users\\Desktop\\24.xml", FileMode.Open))
{
// Call the Deserialize method to restore the object's state.
envelope = (XmlStr.DocumentEnvelope)serializer.Deserialize(reader);
}
// Write out the properties of the object.
Console.WriteLine(envelope.DocumentBody.Invoice.ID.Value);
}
When I use code below, I get error
System.InvalidOperationException: 'There is an error in XML document (2, 2).'
Inner Exception
InvalidOperationException: <DocumentEnvelope xmlns='urn:eFaktura:MinFinrs:envelop:schema'>
was not expected.
XmlSerializer serializer =
new XmlSerializer(typeof(zaglavlje.InvoiceLine[]));
// Declare an object variable of the type to be deserialized.
zaglavlje.InvoiceLine[] envelope;
using (Stream reader = new FileStream(@"C:\\Users\\Desktop\\24.xml", FileMode.Open))
{
// Call the Deserialize method to restore the object's state.
envelope = (zaglavlje.InvoiceLine[])serializer.Deserialize(reader);
}
// Write out the properties of the object.
//Console.WriteLine(envelope);
I would like to get InvoiceLine like this
First loop
ID: 1
InvoicedQuantity: 65
LineExtensionAmount: 3971.5
Item.Name: line 1 description
Price.PriceAmount: 61.1
BaseQuantity: 1
Second loop
ID: 2
InvoicedQuantity: 65
LineExtensionAmount: 2535
Item.Name: line 2 description
Price.PriceAmount: 39
BaseQuantity: 1
CodePudding user response:
Use a customer serialization :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.Schema;
using System.Xml.Linq;
namespace ConsoleApplication2
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(DocumentEnvelope));
DocumentEnvelope envelope = (DocumentEnvelope) serializer.Deserialize(reader);
}
}
[XmlRoot(Namespace = "urn:eFaktura:MinFinrs:envelop:schema")]
public class DocumentEnvelope
{
public DocumentBody DocumentBody { get; set; }
}
public class DocumentBody
{
[XmlElement(Namespace = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2")]
public Invoice Invoice { get; set; }
}
public class Invoice
{
[XmlElement(ElementName = "InvoiceLine", Namespace = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2")]
public List<InvoiceLine> InvoiceLine { get; set; }
}
public class InvoiceLine : IXmlSerializable
{
public int InvoicedQuantity { get; set; }
public decimal LineExtensionAmount { get; set; }
public string ItemName { get; set; }
public decimal PriceAmount { get; set; }
public decimal BaseQuantity { get; set; }
public void WriteXml(XmlWriter writer)
{
}
public void ReadXml(XmlReader reader)
{
XElement invoiceLine = (XElement)XElement.ReadFrom(reader);
XNamespace ns = invoiceLine.Name.Namespace;
InvoicedQuantity = (int)invoiceLine.Elements().Where(x => x.Name.LocalName == "InvoicedQuantity").First();
LineExtensionAmount = (decimal)invoiceLine.Elements().Where(x => x.Name.LocalName == "LineExtensionAmount").First();
ItemName = (string)invoiceLine.Descendants().Where(x => x.Name.LocalName == "Name").FirstOrDefault();
PriceAmount = (decimal)invoiceLine.Descendants().Where(x => x.Name.LocalName == "PriceAmount").FirstOrDefault();
BaseQuantity = (decimal )invoiceLine.Descendants().Where(x => x.Name.LocalName == "BaseQuantity").FirstOrDefault();
}
public XmlSchema GetSchema()
{
return (null);
}
}
}
CodePudding user response:
Thanks @jdweng
I tried your code and works perfectly.
I also managed to adapt my code to get count for InvoiceLine and do for loop.
static void Main(string[] args)
{
XmlSerializer serializer =
new XmlSerializer(typeof(zaglavlje.DocumentEnvelope));
// Declare an object variable of the type to be deserialized.
zaglavlje.DocumentEnvelope envelope;
using (Stream reader = new FileStream(FILENAME, FileMode.Open))
{
// Call the Deserialize method to restore the object's state.
envelope = (zaglavlje.DocumentEnvelope)serializer.Deserialize(reader);
}
int xxx = envelope.DocumentBody.Invoice.InvoiceLine.Count();
for (int i = 0; i < xxx; i )
{
Console.WriteLine("No: " envelope.DocumentBody.Invoice.InvoiceLine[i].ID.Value);
Console.WriteLine("Name: " envelope.DocumentBody.Invoice.InvoiceLine[i].Item.Name);
}