使用Nokogiri从Sinatra文件上传解析临时文件

时间:2011-07-17 15:28:34

标签: xml file-upload sinatra nokogiri xsd-validation

我在thread

上找到了上传文件的代码

我尝试修改它以使用Nokogiri解析tempfile并根据xsd架构验证它,但它总是返回false。

我还将github上的整个项目上传到this site

my.xml

<?xml version="1.0" encoding="ISO-8859-1"?>

 <shiporder orderid="889923"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="my.xsd">
  <orderperson>John Smith</orderperson>
 <shipto>
   <name>Ola Nordmann</name>
   <address>Langgt 23</address>
   <city>4000 Stavanger</city>
   <country>Norway</country>
 </shipto>
 <item>
   <title>Empire Burlesque</title>
   <note>Special Edition</note>
   <quantity>1</quantity>
   <price>10.10</price>
 </item>
 <item>
   <title>Hide your heart</title>
   <quantity>1</quantity>
   <price>9.90</price>
 </item>
</shiporder>

my.xsd

<?xml version="1.0" encoding="ISO-8859-1" ?>
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

 <xs:simpleType name="stringtype">
   <xs:restriction base="xs:string"/>
 </xs:simpleType>

 <xs:simpleType name="inttype">
   <xs:restriction base="xs:positiveInteger"/>
 </xs:simpleType>

 <xs:simpleType name="dectype">
   <xs:restriction base="xs:decimal"/>
 </xs:simpleType>

 <xs:simpleType name="orderidtype">
   <xs:restriction base="xs:string">
     <xs:pattern value="[0-9]{6}"/>
   </xs:restriction>
 </xs:simpleType>

 <xs:complexType name="shiptotype">
   <xs:sequence>
     <xs:element name="name" type="stringtype"/>
     <xs:element name="address" type="stringtype"/>
     <xs:element name="city" type="stringtype"/>
     <xs:element name="country" type="stringtype"/>
   </xs:sequence>
 </xs:complexType>

 <xs:complexType name="itemtype">
   <xs:sequence>
     <xs:element name="title" type="stringtype"/>
     <xs:element name="note" type="stringtype" minOccurs="0"/>
     <xs:element name="quantity" type="inttype"/>
     <xs:element name="price" type="dectype"/>
   </xs:sequence>
 </xs:complexType>

 <xs:complexType name="shipordertype">
   <xs:sequence>
     <xs:element name="orderperson" type="stringtype"/>
     <xs:element name="shipto" type="shiptotype"/>
     <xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
   </xs:sequence>
   <xs:attribute name="orderid" type="orderidtype" use="required"/>
 </xs:complexType>

<xs:element name="shiporder" type="shipordertype"/>

</xs:schema>

config.ru

$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'UserUpload'

run UserUpload

UserUpload.rb

#encoding utf-8

require 'sinatra/base'
require 'haml'
require 'nokogiri'

class UserUpload < Sinatra::Base

  helpers do
    def open_schema
      @myschema = Nokogiri::XML::Schema(File.open('my.xsd'))
    end

    def check_file
     @test = @myschema.valid? (@mytmp)
     @atest = @myschema.validate (@mytmp)
    end

  end

  get '/upload' do
    haml :upload, :layout => false
  end

  post '/upload' do
    unless params[:file] &&
           (tmpfile = params[:file][:tempfile]) &&
           (name = params[:file][:filename])
      @error = "No file selected"
      return haml(:upload)
    end
    STDERR.puts "Uploading file, original name #{name.inspect}"
    while blk = tmpfile.read(65536)
      # read tempfile with nokogiri and validate against xsd schema
      @mytmp = Nokogiri::XML(tmpfile)
      open_schema
      check_file
      STDERR.puts blk.inspect
    end

    "#{@mytmp}" # returns <?xml version="1.0"?>
    #{}"@test = #{@test} @atest = #{@atest}" # @test = false
  end

end

尝试在命令行上针对xsd架构验证xml文件可以正常工作。

xmlreader.rb(ruby script,non-sinatra)

require 'nokogiri'

doc = Nokogiri::XML(File.open('my.xml'))
schema = Nokogiri::XML::Schema(File.open('my.xsd'))
y =  schema.valid? (doc) #returns false if invalid and true if valid
x = schema.validate (doc) #returns a listing of errors
puts "valid? #{y} errors: #{x}"

1 个答案:

答案 0 :(得分:0)

我找到了解决方案:

post '/upload' do
  unless params[:file] &&
       (tmpfile = params[:file][:tempfile]) &&
       (name = params[:file][:filename])
    @error = "No file selected"
    return haml(:upload)
  end
  STDERR.puts "Uploading file, original name #{name.inspect}"
  @mytmp = Nokogiri::XML(tmpfile.read)
  open_schema
  check_file
end