I'm trying to validate a document against the ONIX 2.1 reference schema, which includes the following lines...
<xs:include schemaLocation="ONIX_BookProduct_CodeLists.xsd"/>
<xs:include schemaLocation="ONIX_XHTML_Subset.xsd"/>
When running the validation, I receive this error:
Nokogiri::XML::SyntaxError: Element '{http://www.w3.org/2001/XMLSchema}include': Failed to load the document 'ONIX_BookProduct_CodeLists.xsd' for inclusion.
All of the schema files reside in the same directory. I see a closed ticket that says this problem has been fixed, but I'm still not having any luck on my end.
Can you provide some sample Ruby and XML to reproduce this problem? It should be fixed, but I need to see how to reproduce the error you're getting.
I'm validating against the ONIX 2.1 schema, available here.
The ruby code I was using to do the validation was pretty straightforward:
xsd_path = File.join(RAILS_ROOT,'lib','onix','2.1','ONIX_BookProduct_Release2.1_reference.xsd')
xsd = Nokogiri::XML::Schema(File.read(xsd_path))
instance = Nokogiri::XML(doc)
xsd.validate(instance).each do |error|
valid = false
log "Error: #{error}"
end
A typical XML document we might throw at this:
<?xml version = "1.0" encoding="UTF-8"?>
<!DOCTYPE ONIXmessage SYSTEM "http://www.editeur.org/onix/2.1/reference/onix-international.dtd">
<ONIXMessage xmlns = "http://www.editeur.org/onix/2.1/reference">
<Header>
<FromCompany>OurCompany</FromCompany>
<ToCompany>Ames</ToCompany>
<SentDate>20091203</SentDate>
</Header>
<Product>
<RecordReference>115</RecordReference>
<NotificationType>03</NotificationType>
<ProductIdentifier>
<ProductIDType>01</ProductIDType>
<IDValue>115</IDValue>
</ProductIdentifier>
<ProductForm>BA</ProductForm>
<ProductFormDescription>84</ProductFormDescription>
<Title>
<TitleType>01</TitleType>
<TitleText>30Nov Book Testing</TitleText>
</Title>
<Contributor>
<ContributorRole>A01</ContributorRole>
<PersonNameInverted>Jones, Tom</PersonNameInverted>
</Contributor>
<Language>
<LanguageRole>01</LanguageRole>
<LanguageCode>eng</LanguageCode>
</Language>
<NumberOfPages>16</NumberOfPages>
<BASICMainSubject>ART000000</BASICMainSubject>
<OtherText>
<TextTypeCode>01</TextTypeCode>
<Text></Text>
</OtherText>
<MediaFile>
<MediaFileTypeCode>27</MediaFileTypeCode>
<MediaFileLinkTypeCode>06</MediaFileLinkTypeCode>
<MediaFileLink>20091203213942_115_cover.pdf</MediaFileLink>
</MediaFile>
<MediaFile>
<MediaFileTypeCode>01</MediaFileTypeCode>
<MediaFileLinkTypeCode>06</MediaFileLinkTypeCode>
<MediaFileLink>20091203213942_115_content.pdf</MediaFileLink>
</MediaFile>
<Imprint>
<ImprintName>OurCompany</ImprintName>
</Imprint>
<Publisher>
<PublishingRole>01</PublishingRole>
<PublisherName>OurCompany</PublisherName>
</Publisher>
<PublicationDate>20091203</PublicationDate>
<SalesRights>
<SalesRightsType>01</SalesRightsType>
<RightsTerritory>WORLD</RightsTerritory>
</SalesRights>
<SupplyDetail>
<SupplierName>Ames</SupplierName>
<SupplyToTerritory>WORLD</SupplyToTerritory>
<ReturnsCodeType>02</ReturnsCodeType>
<ReturnsCode>N</ReturnsCode>
<AvailabilityCode>IP</AvailabilityCode>
<OnSaleDate>20091203</OnSaleDate>
<Price>
<PriceTypeCode>01</PriceTypeCode>
<DiscountPercent>40.0</DiscountPercent>
<PriceAmount>0.00</PriceAmount>
<CurrencyCode>USD</CurrencyCode>
</Price>
</SupplyDetail>
</Product>
</ONIXMessage>
Ah, I see the problem. This line:
xsd = Nokogiri::XML::Schema(File.read(xsd_path))
The File.read just returns a string. Nokogiri can't tell from which directory that schema was read. If you pass the Schema constructor an open file handle, it should work. Like this:
xsd_path = File.join(RAILS_ROOT,'lib','onix','2.1','ONIX_BookProduct_Release2.1_reference.xsd')
xsd = Nokogiri::XML::Schema(File.open(xsd_path))
instance = Nokogiri::XML(doc)
xsd.validate(instance).each do |error|
valid = false
log "Error: #{error}"
end
Or if you really want to use File.read you can do it this way:
xsddoc = Nokogiri::XML(File.read(xsd_path), xsd_path)
xsd = Nokogiri::XML::Schema.from_document(xsddoc)
instance = Nokogiri::XML(doc)
xsd.validate(instance).each do |error|
valid = false
log "Error: #{error}"
end
Hope that helps!
I have just been bitten by the same thing and ended-up reading the source code of both Nokogiri and LibXML2 to figure out what went wrong with <include>. Unfortunately I didn't see this closed ticket...
Before loading the xsd it is being parsed as an XML document first and this document's url() is not being set if reading the file as a string instead of as an IO object. The URL is important because this is where the XSD will look for <include>'s.
Nokogiri's API doesn't help much here since the signature is:
new(string_or_io)
The should definitely be documented!
Good! Works for me!
Thnx
Most helpful comment
Ah, I see the problem. This line:
The
File.readjust returns a string. Nokogiri can't tell from which directory that schema was read. If you pass the Schema constructor an open file handle, it should work. Like this:Or if you really want to use
File.readyou can do it this way:Hope that helps!