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

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

I miss you all กับ I miss all of you ต่างกันอย่างไร

ปัญหาและเฉลยวิชาธรรม นักธรรมชั้นตรี สอบในสนามหลวง วันอังคาร ที่ ๒๙ กันยายน พ.ศ.๒๕๕๒

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