I'm trying to validate an XBRL document, but I'm a bit lost. The XBRL is a (simplified) example of the Dutch taxonomy for company tax submits. Here's the XBRL:
string xbrl = #"<xbrli:xbrl xml:lang='nl' xmlns:xbrli='http://www.xbrl.org/2003/instance' xmlns:link='http://www.xbrl.org/2003/linkbase' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:bd-alg='http://www.nltaxonomie.nl/8.0/basis/bd/items/bd-algemeen' xmlns:xbrldi='http://xbrl.org/2006/xbrldi' xmlns:bd-dim-dom='http://www.nltaxonomie.nl/8.0/basis/bd/domains/bd-domains' xmlns:bd-dim-dim='http://www.nltaxonomie.nl/8.0/domein/bd/axes/bd-axes' xmlns:bd-bedr='http://www.nltaxonomie.nl/8.0/basis/bd/items/bd-bedrijven' xmlns:iso4217='http://www.xbrl.org/2003/iso4217'>
<link:schemaRef xlink:type='simple' xlink:href='http://www.nltaxonomie.nl/8.0/report/bd/entrypoints/bd-rpt-vpb-aangifte-2013.xsd' xlink:arcrole='http://www.w3.org/1999/xlink/properties/linkbase'/>
<xbrli:context id='c1'>
<xbrli:entity>
<xbrli:identifier scheme='www.belastingdienst.nl/identificatie'>800030357</xbrli:identifier>
</xbrli:entity>
<xbrli:period>
<xbrli:startDate>2013-07-01</xbrli:startDate>
<xbrli:endDate>2014-06-01</xbrli:endDate>
</xbrli:period>
<xbrli:scenario>
<xbrldi:explicitMember dimension='bd-dim-dim:PartyDimension'>bd-dim-dom:Declarant</xbrldi:explicitMember>
</xbrli:scenario>
</xbrli:context>
<xbrli:context id='c2'>
<xbrli:entity>
<xbrli:identifier scheme='www.belastingdienst.nl/identificatie'>800030357</xbrli:identifier>
</xbrli:entity>
<xbrli:period>
<xbrli:instant>2014-06-01</xbrli:instant>
</xbrli:period>
<xbrli:scenario>
<xbrldi:explicitMember dimension='bd-dim-dim:TimeDimension'>bd-dim-dom:End</xbrldi:explicitMember>
<xbrldi:explicitMember dimension='bd-dim-dim:PartyDimension'>bd-dim-dom:Declarant</xbrldi:explicitMember>
</xbrli:scenario>
</xbrli:context>
<xbrli:unit id='u1'>
<xbrli:measure>iso4217:EUR</xbrli:measure>
</xbrli:unit>
<bd-alg:SoftwarePackageName contextRef='c1'>SoftwareNaame</bd-alg:SoftwarePackageName>
<bd-alg:SoftwarePackageVersion contextRef='c1'>V1</bd-alg:SoftwarePackageVersion>
<bd-alg:TaxReturnMessageType contextRef='c1'>81</bd-alg:TaxReturnMessageType>
<bd-bedr:AssetsTotalAmountFiscal contextRef='c2' decimals='INF' unitRef='u1'>0</bd-bedr:AssetsTotalAmountFiscal>
<bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal contextRef='c1' decimals='INF' unitRef='u1'>0</bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal>
</xbrli:xbrl>";
I use the following code to load the XSD and validate the document:
var doc = XDocument.Parse(xbrl);
var xmlReader = XmlReader.Create("http://www.nltaxonomie.nl/8.0/report/bd/entrypoints/bd-rpt-vpb-aangifte-2013.xsd");
var schema = XmlSchema.Read(xmlReader,
(sender, e) => { throw e.Exception; });
var set = new XmlSchemaSet();
set.Add(schema);
set.Compile();
doc.Validate(set, (sender, e) =>
{
throw new Exception("document validation failed: " + e.Message);
});
This produces the following error message:
document validation failed: The element 'xbrl' in namespace 'http://www.xbrl.org/2003/instance' has invalid child element 'SoftwarePackageName' in namespace 'http://www.nltaxonomie.nl/8.0/basis/bd/items/bd-algemeen'. List of possible elements expected: 'item, tuple, context, unit' in namespace 'http://www.xbrl.org/2003/instance' as well as 'footnoteLink' in namespace 'http://www.xbrl.org/2003/linkbase'.
Apparantly SchemaSet.Compile fails to find all the related XSD's (direct link to the main XSD here). I've been trying different ways of loading the schema and parsing the document for hours now, but I'm not sure how to solve this problem.
I have also tried to read the document with Gepsio. Gepsio loads the document, but doesn't find any facts in the document, so it looks like the structure of the Dutch taxonomy schema is the problem here.
Your XML instance does not validate with that schema. Perhaps it will validate with another schema which imports it, or perhaps you need to create a new schema which imports all the schemas you need.
The problem is that these elements, placed at top level below root, at the end of your file:
<bd-alg:SoftwarePackageName contextRef='c1'>SoftwareNaame</bd-alg:SoftwarePackageName>
<bd-alg:SoftwarePackageVersion contextRef='c1'>V1</bd-alg:SoftwarePackageVersion>
<bd-alg:TaxReturnMessageType contextRef='c1'>81</bd-alg:TaxReturnMessageType>
<bd-bedr:AssetsTotalAmountFiscal contextRef='c2' decimals='INF' unitRef='u1'>0</bd-bedr:AssetsTotalAmountFiscal>
<bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal contextRef='c1' decimals='INF' unitRef='u1'>0</bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal>
are not allowed, according to the schema.
If you believe they should be allowed, probably you are not using the correct schema.
If your application can use a derived type, a solution would be to create a new schema which imports the schema you need, and defines a new root (in a new namespace) which allows the extra elements. If the types in the original schema are exposed, you can also try to redefine the root type in the same namespace.
Related
I have an XML file which starts something like this:-
<?xml version="1.0" encoding="UTF-8"?>
<Deal xmlns="http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<AccountingDate>2019-09-30</AccountingDate>
When I try to convert this object to XML like below, I get an error:-
private static void Prod_Error_Test()
{
string prodRequestXml = File.ReadAllText("ProdXml.xml");
var serializer = new XmlSerializer(typeof(Service.Deal));
Service.Deal request ;
var reader = new StringReader(prodRequestXml);
request = (Service.Deal)serializer.Deserialize(reader);
}
The Error Message is "There is an error in XML document (2, 2).". The Inner Exception Message is "<Deal xmlns='http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models'> was not expected."
Service.Deal is a WCF Proxy.So I may not be able to add any attributes. Can anyone suggest what to do here ?
Being a WCF proxy doesn't preclude adding attributes; in particular, it is usually a partial class, which means you can have your own separate file, with:
namespace Service
{
[XmlRoot("Deal", Namespace = "http://schemas.datacontract.org/2004/07/DealioCapLinkLib.Dealio.Models")]
partial class Deal {}
}
But ultimately: if the type doesn't conveniently fit the XML: stop fighting it - create a new separate type that fits the XML and works well with XmlSerializer, and then map between the two types in your own code.
I'm trying to create an XmlSchemaSet against the SAML 2.0 set of schema definitions, starting with the protocol schema here: https://docs.oasis-open.org/security/saml/v2.0/saml-schema-protocol-2.0.xsd
var set = new XmlSchemaSet();
XmlSchema schema;
using (var reader = XmlReader.Create(
"https://docs.oasis-open.org/security/saml/v2.0/saml-schema-protocol-2.0.xsd"))
{
schema = XmlSchema.Read(reader, (sender, e) => Console.WriteLine(e.Message));
}
set.Add(schema);
set.Compile();
When Compile is called, the following exception is thrown:
System.Xml.Schema.XmlSchemaException
Type 'urn:oasis:names:tc:SAML:2.0:assertion:EncryptedElementType' is not declared.
at System.Xml.Schema.XmlSchemaSet.InternalValidationCallback(Object sender, ValidationEventArgs e)
at System.Xml.Schema.BaseProcessor.SendValidationEvent(XmlSchemaException e, XmlSeverityType severity)
at System.Xml.Schema.BaseProcessor.SendValidationEvent(XmlSchemaException e)
at System.Xml.Schema.Compiler.CompileElement(XmlSchemaElement xe)
at System.Xml.Schema.Compiler.Compile()
at System.Xml.Schema.Compiler.Execute(XmlSchemaSet schemaSet, SchemaInfo schemaCompiledInfo)
at System.Xml.Schema.XmlSchemaSet.Compile()
at XSD.Program.Main(String[] args)
The type specified urn:oasis:names:tc:SAML:2.0:assertion:EncryptedElementType appears in the namespace imported at the top of the schema:
<import
namespace="urn:oasis:names:tc:SAML:2.0:assertion"
schemaLocation="saml-schema-assertion-2.0.xsd"/>
Using Fiddler, I can't see the application making any attempts at retrieving the imported schema.
Why don't these import statements appear to be working with the XmlSchemaSet?
The default behaviour of the XmlSchemaSet is to not try to resolve any external schemas. To this this, the XmlResolver property must be set. The go-to resolver implementation is XmlUrlResolver:
set.XmlResolver = new XmlUrlResolver();
The important thing is to set this property before adding any schemas to the set. The call to Add performs "pre-processing" on the schema, which includes resolving any import statements. Assigning the XmlResolver after calling Add appears to have no effect.
The application code needs to be:
var set = new XmlSchemaSet
{
// Enable resolving of external schemas.
XmlResolver = new XmlUrlResolver()
};
XmlSchema schema;
using (var reader = XmlReader.Create(
"https://docs.oasis-open.org/security/saml/v2.0/saml-schema-protocol-2.0.xsd"))
{
schema = XmlSchema.Read(reader, (sender, e) => Console.WriteLine(e.Message));
}
set.Add(schema);
set.Compile();
NOTE The above code still does not actually produce the desired result due to problems loading the schemas from w3.org, however the imported SAML schema is resolved successfully.
I need to read some XML files that follow the ONIX standard
See: http://www.editeur.org/93/Release-3.0-Downloads/
To do this i downloaded the ONIX 3.0 XSD:
http://www.editeur.org/files/ONIX%203/ONIX_BookProduct_XSD_schema+codes_Issue_25.zip
Using the downloaded XSD and this command "xsd your.xsd /classes" i created classes that i want to use.
When trying to create a new Xml Serializer like so:
var xmls = new XmlSerializer(typeof(Model.ONIX.editeur.ONIXMessage));
I get and exception
"There was an error reflecting type 'Model.ONIX.editeur.ONIXMessage'."
When i drill down through the inner exceptions i end up with this message:
"{"Member 'Text' cannot be encoded using the XmlText attribute. You
may use the XmlText attribute to encode primitives, enumerations,
arrays of strings, or arrays of XmlNode."}"
I am not sure what to do, is something wrong with the XSD? Any suggestions?!
Edit
public static List<Model.ONIX.editeur.Product> GetProductsDataFromOnixFile(string onixFileLocation)
{
var xmls = new XmlSerializer(typeof(Model.ONIX.editeur.ONIXMessageRefname));
using (var reader = XmlReader.Create(onixFileLocation))
{
if (xmls.CanDeserialize(reader))
{
var onixMessage = (Model.ONIX.editeur.ONIXMessage)xmls.Deserialize(reader);
return onixMessage.Items.OfType<Model.ONIX.editeur.Product>().ToList();
}
throw new Exception(string.Format("Cant read the file {0} as Onix", onixFileLocation));
}
}
I know this question is old but I assume others with specific Onix issues will run into this.
Here is how I got it to work.
In the reference xsd are two includes in the top. Here I copy/pasted the other two files in.
<xs:include schemaLocation="ONIX_BookProduct_CodeLists.xsd" />
<xs:include schemaLocation="ONIX_XHTML_Subset.xsd" />
I.e. these lines are replaced in the file with the corresponding file.
Then I did the
xsd ONIX_BookProduct_3.0_reference.xsd /classes
And then it generates the .cs file. And the only issue I had here was I had to remove a text attribute from all fields that was e.g. List147, but not from the fields that was string. E.g. I had to remove the attribute from generated code like this:
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public List121 textscript {
get {
return this.textscriptField;
but not from attributes like this
/// <remarks/>
[System.Xml.Serialization.XmlTextAttribute()]
public string Value {
get {
return this.valueField;
I need to read configuration elements from the web.config.
Let this be my web.config.
<family>
<parents>
<child name="Hello"/>
<child name="World"/>
</parents>
<parents>
<child name="Hello1"/>
<child name="World2"/>
</parents>
</family>
So I have something like this, I need to read this into a collection.
How can i do this????
In general, you can store simple application settings and connection string in web.config (or app.config), but anything more complex, like an object graph or XML (as in your case) and you should consider a different method.
These may be helpful:
How do I store an XML value in my .NET App.Config file
(it suggests encoding the XML in an app setting)
However it would be better to have a separate XML data file and convert it to an object graph using Linq-To-XML (see reference) or XPath and the XmlDocument and related classes.
Edit: see the other answer, which does allow XML in the config file. That's a more direct answer to your exact questions but I will leave this here for reference. On the whole it looks like your data is not configuration data (more like runtime / user data) and does not belong in a .config file: so I would recommend storing it in a separate XML file, and having a config file entry pointing to the filename of the separate XML file.
Hope that helps!
You need to define your own custom configuration section, which will allow you to read the nested configuration element properly. BTW, this is the same method that all the others use, for instance the Enterprise Library components, NHibernate, etc.
The steps you need to take are very straightforward, and a tutorial is provided here:
http://msdn.microsoft.com/en-us/library/2tw134k3.aspx
You need to use the ConfigurationElementCollection Class.
See this sample on the MSDN
public struct Child
{
public string name;
public Child(string name)
{
this.name = name;
}
}
public class Parent
{
public List<Child> childs = new List<Child>();
public static List<Parent> ReadParentsFromXml(string fileName)
{
List<Parent> parents = new List<Parent>();
System.Xml.XmlTextReader doc = new System.Xml.XmlTextReader(fileName);
Parent element = new Parent();
while (doc.Read())
{
switch (doc.Name)
{
case "parents":
if (doc.NodeType == System.Xml.XmlNodeType.EndElement)
{
parents.Add(element);
element = new Parent();
}
break;
case "child":
if(doc.NodeType != System.Xml.XmlNodeType.EndElement)
element.childs.Add(new Child(doc.GetAttribute(0)));
break;
}
}
return parents;
}
}
I don't want to do anything fancy, I just want to make sure a document is valid, and print an error message if it is not. Google pointed me to this, but it seems XmlValidatingReader is obsolete (at least, that's what MonoDevelop tells me).
Edit: I'm trying Mehrdad's tip, but I'm having trouble. I think I've got most of it, but I can't find OnValidationEvent anywhere. Where go I get OnValidationEvent from?
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.DTD;
settings.ValidationEventHandler += new ValidationEventHandler(/*trouble is here*/);
XmlReader validatingReader = XmlReader.Create(fileToLoad, settings);
Instead of creating XmlValidatingReader class directly, you should construct an appropriate XmlReaderSettings object and pass it as an argument to the XmlReader.Create method:
var settings = new XmlReaderSettings { ValidationType = ValidationType.DTD };
settings.ValidationEventHandler += new ValidationEventHandler(OnValidationEvent);
var reader = XmlReader.Create("file.xml", settings);
The rest is unchanged.
P.S. OnValidationEvent is the name of the method you declare to handle validation events. Obviously, you can remove the line if you don't want to subscribe to validation events raised by the XmlReader.
var messages = new StringBuilder();
var settings = new XmlReaderSettings { ValidationType = ValidationType.DTD };
settings.ValidationEventHandler += (sender, args) => messages.AppendLine(args.Message);
var reader = XmlReader.Create("file.xml", settings);
if (messages.Length > 0)
{
// Log Validation Errors
// Throw Exception
// Etc.
}
ValidationEventHandler
Lambda Expressions
Type Inference
I've referred to this example on DTD validation.
https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmlreadersettings.dtdprocessing?view=netcore-3.1#input
This example has invalid DTD XML, which I've corrected as below.
<!--XML file using a DTD-->
<!DOCTYPE store [
<!ELEMENT store (item)*>
<!ELEMENT item (name,dept,price)>
<!ATTLIST item type CDATA #REQUIRED ISBN CDATA
#REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT dept (#PCDATA)>
<!ELEMENT price (#PCDATA)>]>
<store>
<item type="supplies" ISBN="2-3631-4">
<name>paint</name>
<dept>1</dept>
<price>16.95</price>
</item>
</store>
full description:
In Visual Studio .NET, create a new Visual C# Console Application
project named ValidateXml. Add two using statements to the beginning
of Class1.cs as follows:
using System.Xml; // for XmlTextReader and XmlValidatingReader
using System.Xml.Schema; // for XmlSchemaCollection (which is used later)
In Class1.cs, declare a boolean variable named isValid before the
start of the Main method as follows:
private static bool isValid = true; // If a validation error occurs,
// set this flag to false in the
// validation event handler.
Create an XmlTextReader object to read an XML document from a text
file in the Main method, and then create an XmlValidatingReader to
validate this XML data as follows:
XmlTextReader r = new XmlTextReader("C:\\MyFolder\\ProductWithDTD.xml");
XmlValidatingReader v = new XmlValidatingReader(r);
The ValidationType property of the XmlValidatingReader object
indicates the type of validation that is required (DTD, XDR, or
Schema). Set this property to DTD as follows:
v.ValidationType = ValidationType.DTD;
If any validation errors occur, the validating reader generates a
validation event. Add the following code to register a validation
event handler (you will implement the MyValidationEventHandler
method in Step 7):
v.ValidationEventHandler +=
new ValidationEventHandler(MyValidationEventHandler);
Add the following code to read and validate the XML document. If any
validation errors occur, MyValidationEventHandler is called to
address the error. This method sets isValid to false (see Step 8).
You can check the status of isValid after validation to see if the
document is valid or invalid.
while (v.Read())
{
// Can add code here to process the content.
}
v.Close();
// Check whether the document is valid or invalid.
if (isValid)
Console.WriteLine("Document is valid");
else
Console.WriteLine("Document is invalid");
Write the MyValidationEventHandler method after the Main method as
follows:
public static void MyValidationEventHandler(object sender,
ValidationEventArgs args)
{
isValid = false;
Console.WriteLine("Validation event\n" + args.Message);
}
Build and run the application. The application should report that the XML document is valid.
e.g.:
In Visual Studio .NET, modify ProductWithDTD.xml to invalidate it (for example, delete the <AuthorName>M soliman</AuthorName> element).
Run the application again. You should receive the following error message:
Validation event
Element 'Product' has invalid content. Expected 'ProductName'.
An error occurred at file:///C:/MyFolder/ProductWithDTD.xml(4, 5).
Document is invalid