Nokogiri: Included files referenced by relative paths in xml schemas can't be found.

Created on 10 Dec 2009  路  5Comments  路  Source: sparklemotion/nokogiri

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.

Most helpful comment

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!

All 5 comments

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

Was this page helpful?
0 / 5 - 0 ratings