FSharp.Data icon indicating copy to clipboard operation
FSharp.Data copied to clipboard

Cannot read XSD: 'Element not defined'

Open cmeeren opened this issue 7 years ago • 11 comments

I have trouble with a specific XSD: https://docs.oasis-open.org/ubl/os-UBL-2.0/xsd/maindoc/UBL-Invoice-2.0.xsd

The following code:

type Invoice = 
  XmlProvider<
    Schema = "https://docs.oasis-open.org/ubl/os-UBL-2.0/xsd/maindoc/UBL-Invoice-2.0.xsd">

Gives the following error:

Error FS3033: The type provider 'ProviderImplementation.XmlProvider' reported an error: Cannot read sample XSD from 'https://docs.oasis-open.org/ubl/os-UBL-2.0/xsd/maindoc/UBL-Invoice-2.0.xsd': The 'urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2:UBLExtensions' element is not declared.

I can't figure out why. Is this a bug in FSharp.Data, an error in the XSD, or something else?

cmeeren avatar Dec 14 '18 07:12 cmeeren

The error happens resolving imports while compiling the schema. It is not specifically due to how FSharp.Data loads the xsd, since you can reproduce it using plain BCL code:

open System.Xml
open System.Xml.Schema

let parseSchema (xsdUri: string) =
    let schemaSet = XmlSchemaSet()
    use reader = XmlReader.Create(xsdUri)
    schemaSet.Add(null, reader) |> ignore
    schemaSet.Compile()
    schemaSet

I was hoping to make it work by downloading a local copy of each file from here and then loading the xsd from the file system, but it did not work either.

I don't think the xsd is wrong since it's published by oasis, but maybe it uses some very peculiar feature and even the BCL can't cope with it (or at least we need to find a different overload/API to load it).

giacomociti avatar Dec 14 '18 22:12 giacomociti

I see, thanks! It would be fantastic to get to the bottom of this and hopefully support these files. 👍 Unfortunately I have absolutely no knowledge of the implementation of XmlProvider or any other type provider, so I'm afraid I have no contributions to make here.

cmeeren avatar Dec 15 '18 15:12 cmeeren

First we should focus on loading the schema in the context of BCL. StackOverflow may be of help here. Once we have figured out how to do it, we can try to improve the type provider correspondingly.

giacomociti avatar Dec 15 '18 16:12 giacomociti

It works using a local copy of each file and setting the ResolutionFolder parameter:

type Invoice = 
    XmlProvider<Schema = "UBL-Invoice-2.0.xsd", ResolutionFolder="/home/giacomo/Documenti/Repos/TestXsd/UBL-Invoice-2.0/maindoc/">

It's important to have the expected folder structure: the main xsd in maindoc and the incuded schemas in a sibling common folder.

giacomociti avatar Dec 18 '18 23:12 giacomociti

Thanks, it's nice that there is a workaround. But is there any reason this shouldn't work using online files? Does ResolutionFolder need to be used there, too? (And why is ResolutionFolder needed in the first place? Shouldn't the relative paths be understandable/traversable just given the path of the main file?)

cmeeren avatar Dec 19 '18 06:12 cmeeren

The reason why we need ResolutionFolder and a custom resolver is explained in this comment.

There's room for improvement here (and no need to know much about type providers to contribute), but I'm afraid of regressions.

I have manually tested ResolutionFolderResolver with many schemas (and added some ugly code to make it work in a few weird cases). But I've been lazy and did not develop automatic tests (involving files and http).

giacomociti avatar Dec 19 '18 22:12 giacomociti

@giacomociti it appears that the ResolutionFolder parameter requires an absolute path which makes it very un-team and un-CI/CD friendly which pretty much negates my ability to use it as I have developers on Windows & Mac and our build server is Linux so absolute paths kill absolutely. Am I missing something in order to get a relative path to work? I don't understand because the schema parameter works perfectly with a relative URL...

buvinghausen avatar Dec 20 '19 21:12 buvinghausen

error FS3033: The type provider 'ProviderImplementation.XmlProvider' reported an error: Cannot read sample XSD from './Resources/form-c/v3/schemas/eis_FormC_Filer.xsd': Invalid URI: The format of the URI could not be determined.

I would assume you could infer a leading ./ as a file URI

buvinghausen avatar Dec 20 '19 21:12 buvinghausen

I'm afraid we need some help from someone with a better overall understanding of URI resolution in F# Data. I think the error originates here and this is utility code common to all type providers.

Maybe changing UriKind.Absolute to UriKind.RelativeOrAbsolute could help (and when I have some time I'll try this out) but I'm a bit reluctant to propose changes with so little contextual knowledge.

giacomociti avatar Dec 27 '19 20:12 giacomociti

@giacomociti thanks for the response I'll download it locally and see if that change makes a difference and will report back. Unfortunately I'm moving today so it will probably be Monday before I can get to it.

buvinghausen avatar Dec 28 '19 20:12 buvinghausen

Using FSharp.Data, 3.3.3

I confirm that specifying ResolutionFolder fixes error with import in .xsd schema at design-time (in runtime had no error initially)

it appears that the ResolutionFolder parameter requires an absolute path which makes it very un-team and un-CI/CD friendly

@buvinghausen A workaround to not use an absolute path is:

ResolutionFolder = __SOURCE_DIRECTORY__

if .xsd files are in the same folder as .fs one. Or if .xsd files are in Schemas folder:

ResolutionFolder = const(__SOURCE_DIRECTORY__ + "\Schemas")

How to get correct resolution folder of F# Type Provider when referencing assemblies via #load? - Stack Overflow

Brains avatar Feb 06 '21 19:02 Brains