Ruby - บทช่วยสอน XML, XSLT และ XPath
XML คืออะไร?
Extensible Markup Language (XML) เป็นภาษามาร์กอัปเหมือนกับ HTML หรือ SGML สิ่งนี้แนะนำโดย World Wide Web Consortium และมีให้ใช้งานในรูปแบบมาตรฐานเปิด
XML เป็นภาษาโอเพ่นซอร์สแบบพกพาที่ช่วยให้โปรแกรมเมอร์สามารถพัฒนาแอปพลิเคชันที่แอปพลิเคชันอื่นสามารถอ่านได้โดยไม่คำนึงถึงระบบปฏิบัติการและ / หรือภาษาพัฒนาการ
XML มีประโยชน์อย่างยิ่งสำหรับการติดตามข้อมูลจำนวนน้อยถึงปานกลางโดยไม่ต้องใช้แบ็คโบนที่ใช้ SQL
สถาปัตยกรรม XML Parser และ API
มีสองรสชาติที่แตกต่างกันสำหรับตัวแยกวิเคราะห์ XML -
SAX-like (Stream interfaces)- ที่นี่คุณลงทะเบียนการโทรกลับสำหรับเหตุการณ์ที่น่าสนใจจากนั้นให้โปรแกรมแยกวิเคราะห์ดำเนินการผ่านเอกสาร สิ่งนี้มีประโยชน์เมื่อเอกสารของคุณมีขนาดใหญ่หรือคุณมีข้อ จำกัด ด้านหน่วยความจำมันจะแยกวิเคราะห์ไฟล์เมื่ออ่านจากดิสก์และไฟล์ทั้งหมดจะไม่ถูกเก็บไว้ในหน่วยความจำ
DOM-like (Object tree interfaces) - นี่คือคำแนะนำของ World Wide Web Consortium ซึ่งไฟล์ทั้งหมดจะถูกอ่านลงในหน่วยความจำและจัดเก็บในรูปแบบลำดับชั้น (อิงตามต้นไม้) เพื่อแสดงคุณสมบัติทั้งหมดของเอกสาร XML
เห็นได้ชัดว่า SAX ไม่สามารถประมวลผลข้อมูลได้เร็วเท่า DOM เมื่อทำงานกับไฟล์ขนาดใหญ่ ในทางกลับกันการใช้ DOM เพียงอย่างเดียวสามารถฆ่าทรัพยากรของคุณได้โดยเฉพาะอย่างยิ่งหากใช้กับไฟล์ขนาดเล็กจำนวนมาก
SAX เป็นแบบอ่านอย่างเดียวในขณะที่ DOM อนุญาตให้เปลี่ยนแปลงไฟล์ XML เนื่องจาก API ที่แตกต่างกันทั้งสองนี้เสริมซึ่งกันและกันอย่างแท้จริงจึงไม่มีเหตุผลว่าทำไมคุณจึงไม่สามารถใช้ API ทั้งสองสำหรับโครงการขนาดใหญ่ได้
การแยกวิเคราะห์และสร้าง XML โดยใช้ Ruby
วิธีที่ใช้กันทั่วไปในการจัดการ XML คือการใช้ไลบรารี REXML โดย Sean Russell ตั้งแต่ปี 2002 REXML เป็นส่วนหนึ่งของการกระจาย Ruby มาตรฐาน
REXML เป็นตัวประมวลผล Pure-Ruby XML ที่สอดคล้องกับมาตรฐาน XML 1.0 เป็นตัวประมวลผลที่ไม่ผ่านการตรวจสอบความถูกต้องโดยผ่านการทดสอบความสอดคล้องที่ไม่ผ่านการตรวจสอบ OASIS ทั้งหมด
ตัวแยกวิเคราะห์ REXML มีข้อดีเหนือกว่าตัวแยกวิเคราะห์อื่น ๆ ที่มีดังต่อไปนี้ -
- มันเขียนด้วยภาษา Ruby 100 เปอร์เซ็นต์
- สามารถใช้สำหรับการแยกวิเคราะห์ SAX และ DOM
- มีน้ำหนักเบาโค้ดน้อยกว่า 2,000 บรรทัด
- วิธีการและชั้นเรียนนั้นเข้าใจง่ายมาก
- API ที่ใช้ SAX2 และรองรับ XPath แบบเต็ม
- จัดส่งพร้อมการติดตั้ง Ruby และไม่จำเป็นต้องติดตั้งแยกต่างหาก
สำหรับตัวอย่างโค้ด XML ทั้งหมดของเราให้ใช้ไฟล์ XML แบบธรรมดาเป็นอินพุต -
<collection shelf = "New Arrivals">
<movie title = "Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title = "Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
<movie title = "Trigun">
<type>Anime, Action</type>
<format>DVD</format>
<episodes>4</episodes>
<rating>PG</rating>
<stars>10</stars>
<description>Vash the Stampede!</description>
</movie>
<movie title = "Ishtar">
<type>Comedy</type>
<format>VHS</format>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom</description>
</movie>
</collection>
การแยกวิเคราะห์เหมือน DOM
Let 's แรกแยกข้อมูล XML เราในแฟชั่นต้นไม้ เราเริ่มต้นด้วยการกำหนดให้rexml/documentห้องสมุด; บ่อยครั้งที่เราทำการรวม REXML เพื่อนำเข้าสู่เนมสเปซระดับบนสุดเพื่อความสะดวก
#!/usr/bin/ruby -w
require 'rexml/document'
include REXML
xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)
# Now get the root element
root = xmldoc.root
puts "Root element : " + root.attributes["shelf"]
# This will output all the movie titles.
xmldoc.elements.each("collection/movie"){
|e| puts "Movie Title : " + e.attributes["title"]
}
# This will output all the movie types.
xmldoc.elements.each("collection/movie/type") {
|e| puts "Movie Type : " + e.text
}
# This will output all the movie description.
xmldoc.elements.each("collection/movie/description") {
|e| puts "Movie Description : " + e.text
}
สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -
Root element : New Arrivals
Movie Title : Enemy Behind
Movie Title : Transformers
Movie Title : Trigun
Movie Title : Ishtar
Movie Type : War, Thriller
Movie Type : Anime, Science Fiction
Movie Type : Anime, Action
Movie Type : Comedy
Movie Description : Talk about a US-Japan war
Movie Description : A schientific fiction
Movie Description : Vash the Stampede!
Movie Description : Viewable boredom
การแยกวิเคราะห์แบบ SAX
ในการประมวลผลข้อมูลเดียวกันmovies.xmlไฟล์ในรูปแบบที่มุ่งเน้นสตรีมเราจะกำหนดคลาสฟังซึ่งเมธอดจะเป็นเป้าหมายของการเรียกกลับจากโปรแกรมแยกวิเคราะห์
NOTE - ไม่แนะนำให้ใช้การแยกวิเคราะห์แบบ SAX สำหรับไฟล์ขนาดเล็กนี่เป็นเพียงตัวอย่างการสาธิตเท่านั้น
#!/usr/bin/ruby -w
require 'rexml/document'
require 'rexml/streamlistener'
include REXML
class MyListener
include REXML::StreamListener
def tag_start(*args)
puts "tag_start: #{args.map {|x| x.inspect}.join(', ')}"
end
def text(data)
return if data =~ /^\w*$/ # whitespace only
abbrev = data[0..40] + (data.length > 40 ? "..." : "")
puts " text : #{abbrev.inspect}"
end
end
list = MyListener.new
xmlfile = File.new("movies.xml")
Document.parse_stream(xmlfile, list)
สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -
tag_start: "collection", {"shelf"=>"New Arrivals"}
tag_start: "movie", {"title"=>"Enemy Behind"}
tag_start: "type", {}
text : "War, Thriller"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "Talk about a US-Japan war"
tag_start: "movie", {"title"=>"Transformers"}
tag_start: "type", {}
text : "Anime, Science Fiction"
tag_start: "format", {}
tag_start: "year", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "A schientific fiction"
tag_start: "movie", {"title"=>"Trigun"}
tag_start: "type", {}
text : "Anime, Action"
tag_start: "format", {}
tag_start: "episodes", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "Vash the Stampede!"
tag_start: "movie", {"title"=>"Ishtar"}
tag_start: "type", {}
tag_start: "format", {}
tag_start: "rating", {}
tag_start: "stars", {}
tag_start: "description", {}
text : "Viewable boredom"
XPath และ Ruby
อีกวิธีหนึ่งในการดู XML คือ XPath นี่คือภาษาหลอกชนิดหนึ่งที่อธิบายวิธีการค้นหาองค์ประกอบและแอตทริบิวต์เฉพาะในเอกสาร XML โดยถือว่าเอกสารนั้นเป็นโครงสร้างที่เรียงลำดับตามตรรกะ
REXML รองรับ XPath ผ่านคลาสXPath โดยถือว่าการแยกวิเคราะห์แบบต้นไม้ (แบบจำลองวัตถุเอกสาร) ดังที่เราได้เห็นข้างต้น
#!/usr/bin/ruby -w
require 'rexml/document'
include REXML
xmlfile = File.new("movies.xml")
xmldoc = Document.new(xmlfile)
# Info for the first movie found
movie = XPath.first(xmldoc, "//movie")
p movie
# Print out all the movie types
XPath.each(xmldoc, "//type") { |e| puts e.text }
# Get an array of all of the movie formats.
names = XPath.match(xmldoc, "//format").map {|x| x.text }
p names
สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -
<movie title = 'Enemy Behind'> ... </>
War, Thriller
Anime, Science Fiction
Anime, Action
Comedy
["DVD", "DVD", "DVD", "VHS"]
XSLT และ Ruby
มีตัวแยกวิเคราะห์ XSLT สองตัวที่ Ruby สามารถใช้ได้ คำอธิบายสั้น ๆ ของแต่ละรายการมีให้ที่นี่
ทับทิม - ซาบโลตรอน
โปรแกรมแยกวิเคราะห์นี้เขียนและดูแลโดย Masayoshi Takahashi สิ่งนี้เขียนขึ้นสำหรับ Linux OS เป็นหลักและต้องการไลบรารีต่อไปนี้ -
- Sablot
- Iconv
- Expat
คุณสามารถค้นหาโมดูลนี้ได้ที่ Ruby-Sablotron.
XSLT4R
XSLT4R เขียนโดย Michael Neumann และสามารถพบได้ที่ RAA ในส่วน Library ภายใต้ XML XSLT4R ใช้อินเทอร์เฟซบรรทัดคำสั่งที่เรียบง่ายแม้ว่าจะสามารถใช้ภายในแอปพลิเคชันของบุคคลที่สามเพื่อแปลงเอกสาร XML
XSLT4R ต้องการ XMLScan ในการทำงานซึ่งรวมอยู่ในไฟล์เก็บถาวร XSLT4R และซึ่งเป็นโมดูล Ruby 100 เปอร์เซ็นต์ โมดูลเหล่านี้สามารถติดตั้งได้โดยใช้วิธีการติดตั้ง Ruby มาตรฐาน (เช่น Ruby install.rb)
XSLT4R มีไวยากรณ์ต่อไปนี้ -
ruby xslt.rb stylesheet.xsl document.xml [arguments]
หากคุณต้องการใช้ XSLT4R จากภายในแอปพลิเคชันคุณสามารถรวม XSLT และป้อนพารามิเตอร์ที่คุณต้องการได้ นี่คือตัวอย่าง -
require "xslt"
stylesheet = File.readlines("stylesheet.xsl").to_s
xml_doc = File.readlines("document.xml").to_s
arguments = { 'image_dir' => '/....' }
sheet = XSLT::Stylesheet.new( stylesheet, arguments )
# output to StdOut
sheet.apply( xml_doc )
# output to 'str'
str = ""
sheet.output = [ str ]
sheet.apply( xml_doc )
อ่านเพิ่มเติม
สำหรับรายละเอียดที่สมบูรณ์เกี่ยวกับ REXML Parser โปรดดูที่เอกสารมาตรฐานREXML แยกวิเคราะห์เอกสาร
คุณสามารถดาวน์โหลด XSLT4R จากรา Repository