fsprojects / FSharp.Data

F# Data: Library for Data Access
https://fsprojects.github.io/FSharp.Data
Other
815 stars 288 forks source link

Cannot read XSD: 'Element not defined' #1236

Open cmeeren opened 5 years ago

cmeeren commented 5 years ago

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?

giacomociti commented 5 years ago

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).

cmeeren commented 5 years ago

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.

giacomociti commented 5 years ago

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 commented 5 years ago

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.

cmeeren commented 5 years ago

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?)

giacomociti commented 5 years ago

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).

buvinghausen commented 4 years ago

@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 commented 4 years ago

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

giacomociti commented 4 years ago

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.

buvinghausen commented 4 years ago

@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.

Brains commented 3 years ago

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