Ruby - Hướng dẫn sử dụng XML, XSLT và XPath
XML là gì?
Ngôn ngữ đánh dấu mở rộng (XML) là một ngôn ngữ đánh dấu giống như HTML hoặc SGML. Điều này được khuyến nghị bởi World Wide Web Consortium và có sẵn như một tiêu chuẩn mở.
XML là một ngôn ngữ mã nguồn mở, di động cho phép các lập trình viên phát triển các ứng dụng mà các ứng dụng khác có thể đọc được, bất kể hệ điều hành và / hoặc ngôn ngữ phát triển.
XML cực kỳ hữu ích để theo dõi lượng dữ liệu vừa và nhỏ mà không yêu cầu xương sống dựa trên SQL.
Kiến trúc phân tích cú pháp XML và API
Có hai phiên bản khác nhau dành cho trình phân tích cú pháp XML -
SAX-like (Stream interfaces)- Tại đây bạn đăng ký các lệnh gọi lại cho các sự kiện quan tâm và sau đó để trình phân tích cú pháp tiến hành thông qua tài liệu. Điều này hữu ích khi tài liệu của bạn lớn hoặc bạn có giới hạn về bộ nhớ, nó phân tích cú pháp tệp khi nó đọc từ đĩa và toàn bộ tệp không bao giờ được lưu trữ trong bộ nhớ.
DOM-like (Object tree interfaces) - Đây là khuyến nghị của World Wide Web Consortium trong đó toàn bộ tệp được đọc vào bộ nhớ và được lưu trữ ở dạng phân cấp (dựa trên cây) để thể hiện tất cả các tính năng của tài liệu XML.
SAX rõ ràng không thể xử lý thông tin nhanh như DOM khi làm việc với các tệp lớn. Mặt khác, việc sử dụng riêng DOM thực sự có thể giết chết tài nguyên của bạn, đặc biệt nếu được sử dụng trên nhiều tệp nhỏ.
SAX ở chế độ chỉ đọc, trong khi DOM cho phép thay đổi tệp XML. Vì hai API khác nhau này bổ sung cho nhau theo nghĩa đen, không có lý do gì bạn không thể sử dụng cả hai cho các dự án lớn.
Phân tích cú pháp và tạo XML bằng Ruby
Cách phổ biến nhất để thao tác với XML là sử dụng thư viện REXML của Sean Russell. Kể từ năm 2002, REXML đã là một phần của bản phân phối Ruby tiêu chuẩn.
REXML là một bộ xử lý XML thuần Ruby phù hợp với tiêu chuẩn XML 1.0. Nó là một bộ xử lý không xác thực , vượt qua tất cả các bài kiểm tra sự phù hợp không xác thực của OASIS.
Trình phân tích cú pháp REXML có những ưu điểm sau so với các trình phân tích cú pháp có sẵn khác:
- Nó được viết 100 phần trăm bằng Ruby.
- Nó có thể được sử dụng cho cả phân tích cú pháp SAX và DOM.
- Nó có dung lượng nhẹ, ít hơn 2000 dòng mã.
- Các phương thức và lớp học thực sự dễ hiểu.
- API dựa trên SAX2 và hỗ trợ Full XPath.
- Được vận chuyển với cài đặt Ruby và không cần cài đặt riêng.
Đối với tất cả các ví dụ về mã XML của chúng tôi, hãy sử dụng một tệp XML đơn giản làm đầu vào -
<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>
Phân tích cú pháp giống DOM
Đầu tiên hãy phân tích cú pháp dữ liệu XML của chúng ta theo kiểu cây . Chúng tôi bắt đầu bằng cách yêu cầurexml/documentthư viện; thường chúng tôi thực hiện một REXML bao gồm để nhập vào không gian tên cấp cao nhất cho thuận tiện.
#!/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
}
Điều này sẽ tạo ra kết quả sau:
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
Phân tích cú pháp giống SAX
Để xử lý cùng một dữ liệu, movies.xml , tệp theo hướng luồng, chúng ta sẽ xác định một lớp trình nghe có các phương thức sẽ là mục tiêu của các lệnh gọi lại từ trình phân tích cú pháp.
NOTE - Không nên sử dụng phân tích cú pháp giống SAX cho một tệp nhỏ, đây chỉ là một ví dụ demo.
#!/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)
Điều này sẽ tạo ra kết quả sau:
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 và Ruby
Một cách khác để xem XML là XPath. Đây là một loại ngôn ngữ giả mô tả cách định vị các phần tử và thuộc tính cụ thể trong một tài liệu XML, coi tài liệu đó như một cây có thứ tự logic.
REXML có hỗ trợ XPath thông qua lớp XPath . Nó giả định phân tích cú pháp dựa trên cây (mô hình đối tượng tài liệu) như chúng ta đã thấy ở trên.
#!/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
Điều này sẽ tạo ra kết quả sau:
<movie title = 'Enemy Behind'> ... </>
War, Thriller
Anime, Science Fiction
Anime, Action
Comedy
["DVD", "DVD", "DVD", "VHS"]
XSLT và Ruby
Có hai trình phân tích cú pháp XSLT có sẵn mà Ruby có thể sử dụng. Một mô tả ngắn gọn về mỗi loại được đưa ra ở đây.
Ruby-Sablotron
Trình phân tích cú pháp này được viết và duy trì bởi Masayoshi Takahashi. Điều này được viết chủ yếu cho hệ điều hành Linux và yêu cầu các thư viện sau:
- Sablot
- Iconv
- Expat
Bạn có thể tìm thấy mô-đun này tại Ruby-Sablotron.
XSLT4R
XSLT4R được viết bởi Michael Neumann và có thể được tìm thấy tại RAA trong phần Thư viện dưới XML. XSLT4R sử dụng giao diện dòng lệnh đơn giản, mặc dù nó có thể được sử dụng trong ứng dụng của bên thứ ba để chuyển đổi tài liệu XML.
XSLT4R cần XMLScan để hoạt động, được bao gồm trong kho lưu trữ XSLT4R và cũng là một mô-đun Ruby 100%. Các mô-đun này có thể được cài đặt bằng phương pháp cài đặt Ruby tiêu chuẩn (ví dụ: ruby install.rb).
XSLT4R có cú pháp sau:
ruby xslt.rb stylesheet.xsl document.xml [arguments]
Nếu bạn muốn sử dụng XSLT4R từ bên trong ứng dụng, bạn có thể bao gồm XSLT và nhập các tham số bạn cần. Đây là ví dụ -
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 )
Đọc thêm
Để biết chi tiết đầy đủ về Trình phân tích cú pháp REXML, vui lòng tham khảo tài liệu tiêu chuẩn cho Tài liệu Trình phân tích cú pháp REXML .
Bạn có thể tải xuống XSLT4R từ Kho lưu trữ RAA .