HACK#53 Plain Old XML

PoXML เป็นโมดูลที่สามารถใช้แทน SOAP::Lite ในกรณีที่ไม่สามารถติดตั้ง SOAP::Lite ได้
PoXML นับเป็นทางเลือกทางหนึ่งสำหรับท่านที่ไม่สามารถใช้ SOAP::Lite [Hack #52] ได้ ซึ่งอาจจะเป็นด้วยเพราะการติดตั้งที่ยุ่งยากหรืออะไรก็ตามแต่
  • Tip: ผู้รู้เกี่ยวกับ Perl ยืนยันว่าการติดตั้งโมดูลนี้มีขั้นตอนที่ง่ายมาก อย่างไรก็ตาม หลายๆคนแย้งว่า การติดตั้งไม่ได้ง่ายดายอย่างที่กล่าวเอาไว้นัก
PoXML นั้นสามารถใช้แทน SOAP::Lite ได้ในระดับที่ดีพอใช้ โดยการที่ทำงานร่วมกับ SOAP ของ Google ตามแบบ Plain Old XML โดยการใช้ LWP::UserAgent ในการสร้าง HTTP request และใช้ XML::Simple ในการประมวลผล XML แต่ส่วนที่เป็นข้อดีที่สุดก็คือ มีการแก้ไขสคริปต์เพียง 2 บรรทัดเท่านั้น เมื่อมีการใช้งานแทน SOAP::Lite ในการแฮ็กเป้าหมายต่างๆในหนังสือเล่มนี้
โค้ดของ PoXML
ไฟล์ สำคัญที่ใช้ในหัวข้อนี้ก็คือไฟล์ PoXML.pm ซึ่งเป็นเพิร์ลโมดูลเล็กๆที่เหมาะสมที่จะบันทึกเก็บไว้ในไดเรกทอรีเดียวกัน กับสคริปต์ที่ใช้ในการแฮ็ก
ประมวล ผล XML แต่ส่วนที่เป็นข้อดีที่สุดก็คือ มีการแก้ไขสคริปต์เพียง 2 บรรทัดเท่านั้น เมื่อมีการใช้งานแทน SOAP::Lite ในการแฮ็กเป้าหมายต่างๆในหนังสือเล่มนี้
โค้ดของ PoXML
ไฟล์ สำคัญที่ใช้ในหัวข้อนี้ก็คือไฟล์ PoXML.pm ซึ่งเป็นเพิร์ลโมดูลเล็กๆที่เหมาะสมที่จะบันทึกเก็บไว้ในไดเรกทอรีเดียวกัน กับสคริปต์ที่ใช้ในการแฮ็ก
# PoXML.pm
# PoXML [pronounced "plain old xml"] is a dire-need drop-in
# replacement for SOAP::Lite designed for Google Web API hacking.
package PoXML;
use strict;
no strict "refs";
# LWP for making HTTP requests, XML for parsing Google SOAP
use LWP::UserAgent;
use XML::Simple;
# Create a new PoXML
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;
# Parse the XML
my $results = XMLin($soap_response);
# Normalize and drop the unnecessary encoding bits
my $return = $results->{'Body'}->{'doGoogleSearchResponse'}->{return};
foreach ( keys %{$return} ) {
$return->{$_}->{content} and
$return->{$_} = $return->{$_}->{content} || '';
}
my @items;
foreach my $item ( @{$return->{resultElements}->{item}} ) {
foreach my $key ( keys %$item ) {
$item->{$key} = $item->{$key}->{content} || '';
}
push @items, $item;
}
$return->{resultElements} = \@items;
my @categories;
foreach my $key ( keys %{$return->{directoryCategories}->{item}} ) {
$return->{directoryCategories}->{$key} =
$return->{directoryCategories}->{item}->{$key}->{content} || '';
}
# 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
ข้าง ล่างนี้เป็นตัวอย่างสคริปต์ PoXML ในแง่การใช้งาน ซึ่งก็ไม่แตกต่างอะไรไปจากการแฮ็กในหัวข้ออื่นๆในหนังสือเล่มนี้ จะมีแต่ก็เพียงการเน้นข้อความเป็นตัวหนา (bold) ตรงส่วนที่มีการ comment ในบรรทัดที่เดิมใช้กับ SOAP::Lite และแทรกบรรทัดใหม่ เพื่อให้ใช้กับ PoXML ได้เท่านั้น
#!/usr/bin/perl
# poxml_google2csv.pl
# Google Web Search Results via PoXML ("plain old xml") module
# exported to CSV suitable for import into Excel
# Usage: poxml_google2csv.pl "{query}" [> results.csv]
# Your Google API developer's key
my $google_key = 'insert key here';
use strict;
# use SOAP::Lite;
use PoXML;
$ARGV[0]
or die qq{usage: perl poxml_search2csv.pl "{query}"\n};
# my $google_search = SOAP::Lite->service("file:$google_wdsl");
my $google_search = new PoXML;
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 ที่คุณต้องการสร้างขึ้นมา หรือที่ต้องการให้นำผลลัพธ์ไปต่อท้าย (เดิมมีผลลัพธ์อยู่บ้างแล้ว) ตัวอย่างเช่นข้างล่างนี้ใช้ “plain old xml” เป็นคำถาม และกำหนดไฟล์ results.csv เป็นไฟล์รับผลลัพธ์ที่ได้กลับคืนมา
$ perl poxml_google2csv.pl "plain old xml" > results.csv
หรือจะตัดส่วนของ > และ results.csv ออก เพื่อส่งผลลัพธ์ให้ไปแสดงที่หน้าจอเพื่อตรวจสอบก่อนก็ได้
ผลลัพธ์
% perl poxml_google2csv.pl "plain old xml"
"title","url","snippet"
"XML.com: Distributed XML [Sep. 06, 2000]",
"http://www.xml.com/pub/2000/09/06/distributed.html",
" ... extensible. Unlike plain old XML, there's no sense of
constraining what the document can describe by a DTD or schema.
This means ... "
...
"Plain Old Documentation",
"http://axkit.org/wiki/view/AxKit/PlainOldDocumentation",
" ... perlpodspec - Plain Old Documentation: format specification
and notes. ... Examples: =pod This is a plain Pod paragraph. ...
encodings in Pod parsing would be as in XML ... "

การใช้งานและข้อจำกัด
ด้วย วิธีเดียวกันนี้ คุณสามารถดัดแปลงวิธีการแฮ็กด้วย SOAP::Lite ที่ได้อธิบายไว้ในหัวข้อต่างๆ ตลอดหนังสือเล่มนี้ มาเป็นการใช้ PoXML ในการแฮ็กแทนก็ได้ โดยมีข้อกำหนดดังนี้
  1. วางไฟล์ PoXML.pm ไว้ในไดเรกทอรีเดียวกันกับสคริปต์ของเรื่องที่จะแฮ็ก
  2. แทนที่บรรทัดในสคริปต์ที่เป็น use SOAP::Lite; ด้วย use PoXML;
  3. แทนที่ my $google_search = SOAP::Lite->service(“file:$google_wdsl”); ด้วย my $google_search = new PoXML;
อย่าง ไรก็ตาม ยังมีข้อจำกัดในการใช้งานอยู่บ้าง ในขณะที่ PoXML ทำงานได้ดีในการดึงผลลัพธ์รวมทั้งสรุปผลลัพธ์ที่ได้จากการค้นหา แต่ก็ไม่ประสบผลสำเร็จในด้านการรวบรวมผลลัพธ์ในขั้นละเอียดขึ้น (Advanced Result) บางอย่าง เช่น ซึ่งเป็นลิสต์รายการหมวดของไดเรกทอรี เป็นต้น
ดูเพิ่มเติม
NoXML [Hack #54] เป็นทางเลือกในการใช้แทน SOAP::Lite ซึ่งใช้เพียง regular expression ทำงาน โดยไม่ต้องใช้ XML parser แต่อย่างใด
XooMLE [Hack #36] เป็น Third-party service ซึ่งเป็นตัวกลางในการเชื่อมต่อระหว่าง Plain Old XML กับ Google We แก้ไขบทความ b API

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

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

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

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