2013-02-15 69 views
0

嘗試處理來自名爲TeleForm的應用程序的一些XML。這是表單掃描軟件,它抓取數據並將其放入XML中。這是XMLRails Hash.from_xml沒有給出預期的結果

<?xml version="1.0" encoding="ISO-8859-1"?> 
<Records> 
    <Record> 
    <Field id="ImageFilename" type="string" length="14"><Value>00000022000000</Value></Field> 
    <Field id="Criterion_1" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Withdrew" type="string" length="1"></Field> 
    </Record> 

    <Record> 
    <Field id="ImageFilename" type="string" length="14"><Value>00000022000001</Value></Field> 
    <Field id="Criterion_1" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Withdrew" type="string" length="1"></Field> 
    </Record> 
</Records> 

我在其他的系統處理了這個,可能使用我們寫了一個自定義分析器的一個片段。我認爲這在Rails中沒有問題,但我錯了。

與Hash.from_xml或引入nokogiri解析這不給我我希望的結果,我得到:

{"Records"=>{"Record"=>[{"Field"=>["", {"id"=>"Criterion_1", "type"=>"number", "length"=>"2", "Value"=>"3"}, ""]}, 
{"Field"=>["", {"id"=>"Criterion_1", "type"=>"number", "length"=>"2", "Value"=>"3"}, ""]}]}} 

這個花費了太多的時間後,我發現,如果我GSUB出來的類型和長度屬性,我得到我的預期(即使它是錯誤的!我只在第一個記錄節點上刪除)。

{"Records"=>{"Record"=>[{"Field"=>[{"id"=>"ImageFilename", "Value"=>"00000022000000"}, 
{"id"=>"Criterion_1", "type"=>"number", "length"=>"2", "Value"=>"3"}, {"id"=>"Withdrew"}]}, 
{"Field"=>["", {"id"=>"Criterion_1", "type"=>"number", "length"=>"2", "Value"=>"3"}, ""]}]}} 

並無在XML樣樣精通,我認爲XML的這種風格的使用類型和長度屬性正試圖轉換爲數據類型。在這種情況下,我可以理解爲什麼「Withdrew」屬性顯示爲空,但不明白爲什麼「ImageFilename」是空的 - 它是一個14個字符的字符串。

我已經用gsub解決了這個問題,但這是無效的XML嗎?添加一個DTD(TeleForm應該提供的)會給我不同的結果嗎?

編輯

我會提供了一個可能的答案,以我自己的問題與一些代碼編輯。代碼如下一些在一個答案,我也從馬克托馬斯接收功能,但我決定不引入nokogiri,原因如下:

  • XML是一致的,送花兒給人包含相同的代碼(/唱片/錄音/字段)和屬性。
  • 在每個XML文件中可能有幾百條記錄,Nokogiri似乎有點慢,只有26條記錄
  • 我想出瞭如何讓Hash.from_xml給我我所期望的(不喜歡type =「string」 ,但只使用哈希值來填充類。

的XML的擴展版本,一個完整的記錄

<?xml version="1.0" encoding="ISO-8859-1"?> 
<Records> 
    <Record> 
    <Field id="ImageFilename" type="string" length="14"><Value>00000022000000</Value></Field> 
    <Field id="DocID" type="string" length="15"><Value>731192AIINSC</Value></Field> 
    <Field id="FormID" type="string" length="6"><Value>AIINSC</Value></Field> 
    <Field id="Availability" type="string" length="18"><Value>M T W H F S</Value></Field> 
    <Field id="Criterion_1" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_2" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_3" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_4" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_5" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_6" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_7" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_8" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_9" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_10" type="number" length="2"><Value>3</Value></Field> 
    <Field id="Criterion_11" type="number" length="2"><Value>0</Value></Field> 
    <Field id="Criterion_12" type="number" length="2"><Value>0</Value></Field> 
    <Field id="Criterion_13" type="number" length="2"><Value>0</Value></Field> 
    <Field id="Criterion_14" type="number" length="2"><Value>0</Value></Field> 
    <Field id="Criterion_15" type="number" length="2"><Value>0</Value></Field> 
    <Field id="DayTraining" type="string" length="1"><Value>Y</Value></Field> 
    <Field id="SaturdayTraining" type="string" length="1"></Field> 
    <Field id="CitizenStageID" type="string" length="12"><Value>731192</Value></Field> 
    <Field id="NoShow" type="string" length="1"></Field> 
    <Field id="NightTraining" type="string" length="1"></Field> 
    <Field id="Withdrew" type="string" length="1"></Field> 
    <Field id="JobStageID" type="string" length="12"><Value>2292</Value></Field> 
    <Field id="DirectHire" type="string" length="1"></Field> 
    </Record> 
</Records> 

我只與工作流的原型試驗,以取代寫在4D老化系統和Active4D。這個區域處理TeleForm s數據作爲批處理操作來執行,它仍然可以恢復到這種狀態。我只是想在新的Rails實現中合併一些舊的可行的概念。 XML文件位於共享服務器上,可能必須將其移至Web根目錄,然後將某些觸發器設置爲處理文件。

我仍然處於定義階段,但我的模塊/類來處理InterviewForm看起來像這樣,可能會改變(很少有錯誤陷阱,仍然試圖進入測試,我的Ruby不如它應該好):

module Teleform::InterviewForm 

    class Form < Prawn::Document 
    # Not relevant to this question, but this class generates the forms from a Fillable PDF template and 
    # relavant Model(s) data. 
    # These forms, when completed are what is processsed by TeleForms and produces the xml. 
    end 

    class RateForms 
    attr_accessor :records, :results 

    def initialize(xml_path) 
     fields = [] 
     xml = File.read(xml_path) 
     # Hash.from_xml does not like a type of "string" 
     hash = Hash.from_xml(xml.gsub(/type="string"/,'type="text"')) 
     hash["Records"]["Record"].each do |record| 
     #extract the field form each record 
     fields << record["Field"] 
     end 
     @records = [] 
     fields.each do |field| 
     #build the records for the form 
     @records << Record.new(field) 
     end 
     @results = rate_records 
    end 

    def rate_records 
     # not relevant to the qustions but this is where the data is processed and a bunch of stuff takes place 
     return "Any errors" 
    end 
    end 


    class Record 
    attr_accessor(*[:image_filename, :doc_id, :form_id, :availability, :criterion_1, :criterion_2, 
     :criterion_3, :criterion_4, :criterion_5, :criterion_6, :criterion_7, :criterion_8, 
     :criterion_9, :criterion_10, :criterion_11, :criterion_12, :criterion_13, :criterion_14, :criterion_15, 
     :day_training, :saturday_training, :citizen_stage_id, :no_show, :night_training, :withdrew, :job_stage_id, :direct_hire]) 

    def initialize(fields) 
     fields.each do |field| 
     if field["type"] == "number" 
      try("#{field["id"].underscore.to_sym}=", field["Value"].to_i) 
     else 
      try("#{field["id"].underscore.to_sym}=", field["Value"]) 
     end 
     end 
    end 
    end 

end 
+0

想要什麼數據,您解壓? – 2013-02-15 23:07:02

+0

真的只是記錄的id和價值。我將長度屬性名稱更改爲tf_length以獲取字符串以顯示我然後只是遍歷數組/ has並生成散列數組。 – appleII717 2013-02-15 23:27:42

+0

等待,每個記錄有3個ID和2個值。你想要哪一個? – 2013-02-16 00:44:23

回答

0

感謝您添加附加信息,這是對受訪者的評分。在你的代碼中使用這個域信息可能會改善它。您尚未發佈任何代碼,但通常使用域對象會導致更簡潔,更易讀的代碼。 我建議創建一個簡單的類代表Rating,而不是從XML數據轉換爲數據結構。

class Rating 
    attr_accessor :image_filename, :criterion_1, :withdrew 
end 

使用上述類,下面是一種使用Nokogiri從XML中提取字段的方法。現在

doc = Nokogiri::XML(xml) 
ratings = [] 

doc.xpath('//Record').each do |record| 
    rating = Rating.new 
    rating.image_filename = record.at('Field[@id="ImageFilename"]/Value/text()').to_s 
    rating.criterion_1 = record.at('Field[@id="Criterion_1"]/Value/text()').to_s 
    rating.withdrew = record.at('Field[@id="Withdrew"]/Value/text()').to_s 
    ratings << rating 
end 

ratingsRating對象,每個方法來檢索數據的列表。這比深入研究深層數據結構要乾淨得多。你甚至可以改善對Rating類此外,例如創建一個withdrew?方法返回一個true或false。

+0

謝謝。我沒有使用Nokogiri太多,但這個答案可能讓我開始。我已經有了一個InterviewForm類,它生成了PDF(Prawn)並對XML解析結果進行了評分。我現在將它重構爲一個包含每個函數的類的模塊。 Nokogiri看起來有點慢,但正如你所說的那樣更清晰的代碼。我認爲我看到了滿足我需求的中間道路。關於Hash.from_xml沒有太多的文檔,但它不能將「string」識別爲類型,將其更改爲「text」可獲得預期的結果。當我接近我的solvo時,我會發佈一個編輯。 – appleII717 2013-02-17 15:56:42

+0

我加入了我的道路答案的中間作爲編輯。 – appleII717 2013-02-17 23:19:39

0

看起來'XmlSimple'(通過maik)[https://github.com/maik/xml-simple]更適合於這個任務,然後是不可靠和不一致的Hash.from_xml實現。

相同的名稱,其中有幾個顯着的優點的嘗試和測試的perl模塊的端口。

  • 是一致的,無論你找到一個節點的一個或多個出現
  • 不嗆和斷章取義的結果
  • 能夠TE屬性和節點內容進行區分。

通過解析器運行上面相同的XML文檔:

XmlSimple.xml_in xml 

將產生以下結果。

{"Record"=> 
    [{"Field"=> 
    [{"id"=>"ImageFilename", "type"=>"string", "length"=>"14", "Value"=>["00000022000000"]}, 
     {"id"=>"DocID", "type"=>"string", "length"=>"15", "Value"=>["731192AIINSC"]}, 
     {"id"=>"FormID", "type"=>"string", "length"=>"6", "Value"=>["AIINSC"]}, 
     {"id"=>"Availability", "type"=>"string", "length"=>"18", "Value"=>["M T W H F S"]}, 
     {"id"=>"Criterion_1", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_2", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_3", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_4", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_5", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_6", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_7", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_8", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_9", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_10", "type"=>"number", "length"=>"2", "Value"=>["3"]}, 
     {"id"=>"Criterion_11", "type"=>"number", "length"=>"2", "Value"=>["0"]}, 
     {"id"=>"Criterion_12", "type"=>"number", "length"=>"2", "Value"=>["0"]}, 
     {"id"=>"Criterion_13", "type"=>"number", "length"=>"2", "Value"=>["0"]}, 
     {"id"=>"Criterion_14", "type"=>"number", "length"=>"2", "Value"=>["0"]}, 
     {"id"=>"Criterion_15", "type"=>"number", "length"=>"2", "Value"=>["0"]}, 
     {"id"=>"DayTraining", "type"=>"string", "length"=>"1", "Value"=>["Y"]}, 
     {"id"=>"SaturdayTraining", "type"=>"string", "length"=>"1"}, 
     {"id"=>"CitizenStageID", "type"=>"string", "length"=>"12", "Value"=>["731192"]}, 
     {"id"=>"NoShow", "type"=>"string", "length"=>"1"}, 
     {"id"=>"NightTraining", "type"=>"string", "length"=>"1"}, 
     {"id"=>"Withdrew", "type"=>"string", "length"=>"1"}, 
     {"id"=>"JobStageID", "type"=>"string", "lth"=>"12", "Value"=>["2292"]}, 
     {"id"=>"DirectHire", "type"=>"string", "length"=>"1"}] 
    }] 
} 

我考慮解決這個問題,並提供與from_xml工作實施Hash和希望能找到別人的一些反饋誰得出了相同的結論。當然,我們並不是唯一有這些挫折的人。

在我們可能會知道尋找慰藉其間有東西比Nokogiri重量更輕,完整的廚房水槽完成這個任務。

nJoy!

相關問題