HACK#54 NoXML อีกทางเลือกหนึ่งสำหรับใช้แทน SOAP::Lite

NoXML เป็นทางเลือกในการใช้แทน SOAP::Lite ซึ่งใช้เพียง regular expression ทำงาน โดยไม่ต้องมี XML parser แต่อย่างใด
NoXML เป็นอีกโมดูลหนึ่ง ที่ใช้แทน SOAP::Lite ได้ ซึ่ง NOXML นี้จะใช้เพียง regular expression ทำงาน โดยปราศจาก XML parser ทุกชนิด ดังที่ชื่อของโมดูลนี้ได้แนะนำไว้
ถ้าหากคุณมีเพียงความรู้พื้นฐานในการติดตั้ง Perl เพื่อใช้งานของคุณเองเท่านั้น รวมทั้งไม่มีทั้ง SOAP::Lite [Hack #52] และ XML::Parser แล้วล่ะก็ NoXML นับเป็นทางเลือกที่ดีทีเดียวสำหรับการแฮ็กเกือบจะทั้งหมดในหนังสือเล่มนี้
  • Tip: ผู้เชี่ยวชาญ XML บางท่านยืนยันว่า ไม่มีอะไรมาแทนที่ XML parser จริงๆได้ ซึ่งเป็นสิ่งที่ถูกต้องอย่างยิ่ง เพราะยังมีประเด็นเรื่องการ Encode และ Hierarchy ที่ regular expression-based parser ไม่สามารถทำได้ แต่สำหรับตัว NOXML นั้นก็ยังเป็นตัวที่ง่ายที่สุดสำหรับการใช้งานและติดตั้ง
NoXML สามารถใช้แทน SOAP::Lite โดยการแก้ไขสคริปต์ที่ใช้ในการแฮ็กเพียงเล็กน้อยเท่านั้น
โค้ดของ NoXML
ไฟล์สำคัญในการแฮ็กในหัวข้อนี้ก็คือ NoXML.pm ซึ่งควรจะบันทึกลงในไดเรกทอรีเดียวกันกับสคริปต์ที่ใช้ในการแฮ็ก

# NoXML.pm
# NoXML [pronounced "no xml"] is a dire-need drop-in
# replacement for SOAP::Lite designed for Google Web API hacking.
package NoXML;
use strict;
no strict "refs";
# LWP for making HTTP requests, XML for parsing Google SOAP
use LWP::UserAgent;
use XML::Simple;
# Create a new NoXML
sub new {
my $self = {};
bless($self);
return $self;
}
# Replacement for the SOAP::Lite-based doGoogleSearch method
sub doGoogleSearch {
my($self, %args);
($self, @args{qw/ key q start maxResults filter restrict
safeSearch lr ie oe /}) = @_;
# grab SOAP request from _ _DATA_ _
my $tell = tell(DATA);
my $soap_request = join '', ;
seek(DATA, $tell, 0);
$soap_request =~ s/\$(\w+)/$args{$1}/ge; #interpolate variables
# Make (POST) a SOAP-based request to Google
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(POST => 'http://api.google.com/search/beta2');
$req->content_type('text/xml');
$req->content($soap_request);
my $res = $ua->request($req);
my $soap_response = $res->as_string;
# Drop the HTTP headers and so forth until the initial xml element
$soap_response =~ s/^.+?(<\?xml)/$1/migs;
# Drop element namespaces for tolerance of future prefix changes
$soap_response =~ s!(<\/?)[\w-]+?:([\w-]+?)!$1$2!g;
# Set up a return dataset
my $return;
# Unescape escaped HTML in the resultset
my %unescape = ('<'=>'<', '>'=>'>', '&'=>'&amp;', '"'=>'"', '''=>"'");
my $unescape_re = join '|' => keys %unescape;
# Divide the SOAP response into the results and other metadata
my($before, $results, $after) = $soap_response =~
m#(^.+)(.+?)(.+$)#migs ;
my $before_and_after = $before . $after;
# Glean as much metadata as possible (while being somewhat lazy ;-)
while ($before_and_after =~ m#([^<]*?)<#migs) {
$return->{$1} = $3; # pack the metadata into the return dataset
}
# Glean the results
my @results;
while ($results =~ m#(.+?)#migs) {
my $item = $1;
my $pairs = {};
while ( $item =~ m#([^<]*)#migs ) {
my($element, $value) = ($1, $2);
$value =~ s/($unescape_re)/$unescape{$1}/g;
$pairs->{$element} = $value;
}
push @results, $pairs;
}
# Pack the results into the return dataset
$return->{resultElements} = \@results;
# Return nice, clean, usable results
return $return;
}
1;
# This is the SOAP message template sent to api.google.com. Variables
# signified with $variablename are replaced by the values of their
# counterparts sent to the doGoogleSearch subroutine.
_ _DATA_ _
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
$key
$q
$start
$maxResults
$filter
$restrict
$safeSearch
$lr
$ie
$oe

ข้าง ล่างนี้เป็นตัวอย่างสคริปต์ NoXML ในแง่การใช้งาน ซึ่งก็ไม่แตกต่างอะไรไปจากการแฮ็กในหัวข้ออื่นๆในหนังสือเล่มนี้ จะมีก็เพียงแต่การเน้นข้อความเป็นตัวหนา (bold) ตรงส่วนที่มีการ comment บรรทัดเดิมที่ใช้กับ SOAP::Lite และแทรกบรรทัดใหม่ เพื่อให้ใช้กับ PoXML ได้เท่านั้น
#!/usr/bin/perl
# noxml_google2csv.pl
# Google Web Search Results via NoXML ("no xml") module
# exported to CSV suitable for import into Excel
# Usage: noxml_google2csv.pl "{query}" [> results.csv]
# Your Google API developer's key
my $google_key='insert key here';
use strict;
# use SOAP::Lite;
use NoXML;
$ARGV[0]
or die qq{usage: perl noxml_search2csv.pl "{query}"\n};
# my $google_search = SOAP::Lite->service("file:$google_wdsl");
my $google_search = new NoXML;
my $results = $google_search ->
doGoogleSearch(
$google_key, shift @ARGV, 0, 10, "false",
"", "false", "", "latin1", "latin1"
);
@{$results->{'resultElements'}} or die('No results');
print qq{"title","url","snippet"\n};
foreach (@{$results->{'resultElements'}}) {
$_->{title} =~ s!"!""!g; # double escape " marks
$_->{snippet} =~ s!"!""!g;
my $output = qq{"$_->{title}","$_->{URL}","$_->{snippet}"\n};
$output =~ s!<.+?>!!g; # drop all HTML tags
print $output;
}
Running the Hack
รัน สคริปต์นี้ที่ command line โดยการใส่คำถามลงไปที่ command line และระบุให้แสดงผลลัพธ์ในไฟล์ CSV ที่คุณต้องการสร้างขึ้นมา หรือที่ต้องการให้นำผลลัพธ์ไปต่อท้าย (appending) ตัวอย่างเช่นข้างล่างนี้ใช้ “no xml” เป็นคำถาม และกำหนดให้ไฟล์ results.csv เป็นไฟล์รับผลลัพธ์ที่ได้กลับคืนมา
$ perl noxml_google2csv.pl "no xml" > results.csv
หรือจะตัดส่วนของ > และ results.csv ออก เพื่อส่งผลลัพธ์ให้ไปแสดงที่หน้าจอเพื่อตรวจสอบก่อนก็ได้ และเห็นผลลัพธ์ทันที
ผลลัพธ์
% perl noxml_google2csv.pl "no xml"
"title","url","snippet"
"site-comments@w3.org from January 2002: No XML specifications",
"http://lists.w3.org/Archives/Public/site-comments/2002Jan/0015.html",
"No XML specifications. From: Prof. ... Next message: Ian B. Jacobs:
"Re: No XML specifications"; Previous message: Rob Cummings:
"Website design..."; ... "
...
"Re: [xml] XPath with no XML Doc",
"http://mail.gnome.org/archives/xml/2002-March/msg00194.html",
" ... Re: [xml] XPath with no XML Doc. From: "Richard Jinks"
; To: ; Subject:
Re: [xml] XPath with no XML Doc; ... "
การใช้งานและข้อจำกัด
ด้วย วิธีเดียวกันนี้ คุณสามารถดัดแปลงวิธีการแฮ็กด้วย SOAP::Lite ที่ได้อธิบายไว้ในหัวข้อต่างๆ ตลอดหนังสือเล่มนี้ มาเป็นการใช้ PoXML ในการแฮ็กแทนก็ได้ โดยมีข้อกำหนดดังนี้
  1. วางไฟล์ NoXML.pm ไว้ในไดเรกทอรีเดียวกันกับสคริปต์ของเรื่องที่จะแฮ็ก
  2. แทนที่บรรทัดในสคริปต์ที่เป็น use SOAP::Lite; ด้วย use NoXML;
  3. แทนที่ my $google_search = SOAP::Lite->service(“file:$google_wdsl”); ด้วย my $google_search = new NoXML;
อย่าง ไรก็ตาม ยังมีข้อจำกัดในการใช้งานอยู่บ้าง ในขณะที่ NoXML ทำงานได้ดีในการดึงผลลัพธ์รวมทั้งสรุปผลลัพธ์ที่ได้จากการค้นหา แต่ก็ไม่ประสบผลสำเร็จในด้านการรวบรวมผลลัพธ์ในขั้นละเอียดขึ้น (advanced result) บางอย่าง เช่น เป็นต้น
ดูเพิ่มเติม
PoXML [Hack #53] เป็นทางเลือกในการใช้ plain old XML แทน SOAP::Lite
XooMLE [Hack #36] เป็น third-party service ซึ่งเป็นตัวกลาในการ interface ระหว่าง Plain Old XML กับ Google Web API

โพสต์ยอดนิยมจากบล็อกนี้

ปัญหาและเฉลยธรรม นักธรรมชั้นโท สอบในสนามหลวง พ.ศ. ๒๕๔๓ วันพฤหัสบดี ที่ ๑๖ พฤศจิกายน พ.ศ. ๒๕๔๓

ปัญหาและเฉลยวินัยบัญญัติ นักธรรมชั้นเอก สอบในสนามหลวง พ.ศ. ๒๕๔๓ วันเสาร์ ที่ ๑๘ พฤศจิกายน พ.ศ. ๒๕๔๓

ปัญหาและเฉลยวิชาธรรม นักธรรมชั้นโท สอบในสนามหลวง วันเสาร์ ที่ ๑๙ พฤศจิกายน พ.ศ. ๒๕๔๘