I implement objects for their further serialization in xml code.
sample code i should get:
<cbc:ID schemeID="urn:oioubl:id:taxschemeid-1.1">63</cbc:ID>
this is how i implemented it in c#:
public class TaxScheme
{
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public TaxSchemeId ID { get; set; }
//...
}
public class TaxSchemeId
{
[XmlAttribute("schemeID")]
public string SchemeID { get; set; }
[XmlText]
public string Value { get; set; }
public TaxSchemeId(string value)
{
SchemeID = "urn:oioubl:id:taxschemeid-1.1";
Value = value;
}
public TaxSchemeId()
{
}
}
I get this error on startup:
InvalidOperationException: The top XML element 'ID' from namespace 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2' references distinct types System.String and ex1.V1.Tax.TaxSchemeId. Use XML attributes to specify another XML name or namespace for the element or types.
if you comment out the "ID" property, then there are no problems with serialization
i tried to do it with attributes:
[XmlElement(ElementName ="ID",Namespace = XML_Namespaces_OIOUBL2.CDC)]
public TaxSchemeId TaxSchemeId { get; set; }
&
[XmlElement(ElementName ="ID", Type = typeof(TaxSchemeId),Namespace = XML_Namespaces_OIOUBL2.CDC)]
public TaxSchemeId TaxSchemeId { get; set; }
but didn't help.
the id property should only write in large, because I need to implement the OIOUBL standard.
from ideas that is but did not try:
change property name (eg TaxSchemeId) ->
take the resulting xml file ->
and replace the name with the desired one (.Replace("TaxSchemeId", "ID")
)
UPD
code to run
the problem is that I use the name ID
more than once:
using System;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
// sample code i want to get
//< cac:TaxTotal >
// < cbc:TaxAmount currencyID = "DKK" > 37.50 </ cbc:TaxAmount >
// < cac:TaxSubtotal >
// < cbc:TaxableAmount currencyID = "DKK" > 150.00 </ cbc:TaxableAmount >
// < cbc:TaxAmount currencyID = "DKK" > 37.50 </ cbc:TaxAmount >
// < cac:TaxCategory >
// < cbc:ID schemeID = "urn:oioubl:id:taxcategoryid-1.1" schemeAgencyID="320">StandardRated</cbc:ID >
// < cbc:Percent > 25.00 </ cbc:Percent >
// < cac:TaxScheme >
// < cbc:ID schemeID = "urn:oioubl:id:taxschemeid-1.1" > 63 </ cbc:ID >
// < cbc:Name > Moms </ cbc:Name >
// < cbc:CurrencyCode > DKK </ cbc:CurrencyCode >
// </ cac:TaxScheme >
// </ cac:TaxCategory >
// </ cac:TaxSubtotal >
//</ cac:TaxTotal >
public class Program
{
public static void Main()
{
Invoice invoice = new Invoice()
{
TaxTotal = new TaxTotal()
{
TaxAmount = new MonetaryValue("DKK", 40.00M),
TaxSubtotal = new TaxSubtotal()
{
TaxableAmount = new MonetaryValue("DKK", 40.00M),
TaxAmount = new MonetaryValue("DKK", 40.00M),
TaxCategory = new TaxCategory()
{
ID = new TaxCategoryId(),
Percent = 25.00m,
TaxScheme = new TaxScheme()
{
ID = new TaxSchemeId("63"),
Name = "Moms",
CurrencyCode = "DKK"
}
}
}
}
};
SerializeAndPrintToConsole(invoice);
Console.WriteLine("Hello World");
}
public static void SerializeAndPrintToConsole(Invoice taxScheme)
{
XmlSerializer serializer = new XmlSerializer(typeof(Invoice));
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("cac", "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2");
namespaces.Add("cbc", "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");
namespaces.Add("ccts", "urn:oasis:names:specification:ubl:schema:xsd:CoreComponentParameters-2");
namespaces.Add("udt", "urn:un:unece:uncefact:data:specification:UnqualifiedDataTypesSchemaModule:2");
namespaces.Add("", "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2");
StringWriter stringWriter = new StringWriter();
serializer.Serialize(stringWriter, taxScheme, namespaces);
string xmlString = stringWriter.ToString();
Console.WriteLine("Serialized XML:");
Console.WriteLine(xmlString);
}
}
public class TaxScheme
{
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public TaxSchemeId ID { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public string Name { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public string CurrencyCode { get; set; }
}
public class TaxSchemeId
{
[XmlAttribute("schemeID")]
public string SchemeID { get; set; }
[XmlText]
public string Value { get; set; }
public TaxSchemeId(string value)
{
SchemeID = "urn:oioubl:id:taxschemeid-1.1";
Value = value;
}
public TaxSchemeId() { }
}
[XmlRoot(Namespace = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2")]
public class Invoice
{
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CAC)]
public TaxTotal TaxTotal { get; set; }
}
public class TaxTotal
{
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public MonetaryValue TaxAmount { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CAC)]
public TaxSubtotal TaxSubtotal { get; set; }
}
public class TaxSubtotal
{
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public MonetaryValue TaxableAmount { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public MonetaryValue TaxAmount { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CAC)]
public TaxCategory TaxCategory { get; set; }
}
public class TaxCategory
{
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public TaxCategoryId ID { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CDC)]
public decimal Percent { get; set; }
[XmlElement(Namespace = XML_Namespaces_OIOUBL2.CAC)]
public TaxScheme TaxScheme { get; set; }
}
public class TaxCategoryId
{
[XmlAttribute("schemeID")]
public string SchemeID { get; set; }
[XmlAttribute("schemeAgencyID")]
public string SchemeAgencyID { get; set; }
[XmlText]
public string Value { get; set; }
public TaxCategoryId()
{
SchemeID = "urn:oioubl:id:taxcategoryid-1.1";
SchemeAgencyID = "320";
Value = "test";
}
}
public class MonetaryValue
{
[XmlAttribute("currencyID")]
public string CurrencyID { get; set; }
[XmlText]
public decimal Value { get; set; }
public MonetaryValue(string currencyID, decimal value)
{
CurrencyID = currencyID;
Value = value;
}
public MonetaryValue(){}
}
public static class XML_Namespaces_OIOUBL2
{
public const string CDC = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
public const string CAC = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2";
}
You seem to have encountered a bug in
XmlSerializer
. If I simply add[XmlRoot(Namespace = XML_Namespaces_OIOUBL2.CDC)]
to eitherTaxScheme
orTaxCategory
:Then the problem goes away. See demo fiddle #1 here.
You may wish to report an issue about this, as the problem seems related but not identical to:
Unfortunately this is not a correct fix, because, according to http://www.datypic.com/,
cac:TaxScheme
andcac:TaxCategory
should both be in yourXML_Namespaces_OIOUBL2.CAC
namespace (i.e.urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2
) when serialized independently, rather thanXML_Namespaces_OIOUBL2.CDC
. And, unfortunately, applying[XmlRoot(Namespace = XML_Namespaces_OIOUBL2.CAC)]
to either or both types does not resolve the problem.As an alternative, I noticed that your two types
TaxCategoryId
andTaxSchemeId
correspond to the same UBL 2.1 typecbc:ID
. So I introduced anID
type corresponding tocbc:ID
along with some factory methods to create them:And modified your data model to use this new type and to include the appropriate
XmlRootAttribute.Namespace
values:Then created an
Invoice
as follows:And now your
SerializeAndPrintToConsole(Invoice taxScheme)
was able to serialize the modified data model usingXmlSerializer
successfully. This appears to be a correct fix, as all C# types are assigned to correct UBL 2.1 namespaces.Notes:
Your type
MonetaryValue
is being used for bothcbc:TaxAmount
andcbc:TaxableAmount
. While their contents are the same, their type names are not, so you may need to separate them in the future.I renamed
XML_Namespaces_OIOUBL2.CDC
toXML_Namespaces_OIOUBL2.CBC
to be consistent with UBL 2.1 naming conventions.Demo fiddle #2 here.