2010-07-12 16 views
5

मेरा प्रश्न है: एक्सएमएल के लिए कुछ तर्क कैसे पास करें: टिग के हैंडलर, और हैंडलर से परिणाम कैसे वापस करें।मैं एक्सएमएल :: ट्विग के हैंडलर के साथ तर्क कैसे पास कर सकता हूं और मूल्य वापस कर सकता हूं?

<counter name = "music", report type = "month", stringSet index = 4>:

यहाँ मेरी कोड है, जो hardcoded है।

तर्क $counter_name, $type, $id का उपयोग करके इसे कैसे कार्यान्वित करें? और string_list के परिणाम को वापस कैसे करें? धन्यवाद (खेद है कि मैंने xml फ़ाइल यहां पोस्ट नहीं की है क्योंकि मुझे ऐसा करने में कुछ परेशानी है। < और> के भीतर कुछ भी अनदेखा कर दिया गया है)।

use XML::Twig; 

sub parse_a_counter { 

    my ($twig, $counter) = @_; 
    my @report = $counter->children('report[@type="month"]'); 

    for my $report (@report){ 

     my @stringSet = $report->children('stringSet[@index=”4”]'); 
     for my $stringSet (@stringSet){ 

      my @string_list = $stringSet->children_text('string'); 
      print @string_list; # in fact I want to return this string_list, 
            # not just print it. 
     } 
    } 

    $counter->flush; # free the memory of $counter 
} 

my $roots = { 'counter[@name="music"]' => 1 }; 

my $handlers = { counter => \&parse_a_counter }; 

my $twig = new XML::Twig(TwigRoots => $roots, 
         TwigHandlers => $handlers); 

$twig->parsefile('counter_test.xml'); 
+0

@ lilili07: SO में आपका स्वागत है। मैंने आपके कोड को स्वरूपित किया है, आप इसे बैकटिक्स में संलग्न करके एक्सएमएल शामिल कर सकते हैं। अगर मैंने गलती की है तो इसे संपादित करने के लिए स्वतंत्र महसूस करें। – Zaid

उत्तर

1

अस्वीकरण: मैं अपने आप को टहनी का इस्तेमाल किया है नहीं है, तो यह जवाब मुहावरेदार नहीं हो सकता है - यह एक सामान्य जवाब "कैसे मैं एक कॉलबैक हैंडलर में राज्य रख कर" है।

तीन में और संचालकों से जानकारी गुजर के तरीके हैं:

एक। राज्य में एक स्थिर स्थान

package TwigState; 

my %state =(); 
# Pass in a state attribute to get 
sub getState { $state{$_[0]} } 
# Pass in a state attribute to set and a value 
sub setState { $state{$_[0]} = $_[1]; } 

package main; 

sub parse_a_counter { # Better yet, declare all handlers in TwigState 
    my ($twig, $element) = @_; 
    my $counter = TwigState::getState('counter'); 
    $counter++; 
    TwigState::setState('counter', $counter); 
} 

दो में आयोजित। राज्य कुछ "राज्य" सदस्य

# Ideally, XML::Twig or XML::Parser would have a "context" member 
# to store context and methods to get/set that context. 
# Barring that, simply make one, using a VERY VERY bad design decision 
# of treating the object as a hash and just making a key in that hash. 
# I'd STRONGLY not recommend doing that and choosing #1 or #3 instead, 
# unless there's a ready made context data area in the class. 
sub parse_a_counter { 
    my ($twig, $element) = @_; 
    my $counter = $twig->getContext('counter'); 
    # BAD: my $counter = $twig->{'_my_context'}->{'counter'}; 
    $counter++; 
    TwigState::setState('counter', $counter); 
    $twig->setContext('counter', $counter); 
    # BAD: $twig->{'_my_context'}->{'counter'} = $counter; 
} 

# for using DIY context, better pass it in with constructor: 
my $twig = new XML::Twig(TwigRoots => $roots, 
         TwigHandlers => $handlers 
         _my_context => {}); 

तीन में एक $ टी (एक्सएमएल :: टहनी वस्तु) अपने आप में आयोजित किया। हैंडलर को closure बनाएं और इसे

+0

मैं बाद में एक बंद उदाहरण जोड़ने की योजना बना रहा था, लेकिन ऐसा लगता है कि मुझे अलग जवाब में मुझे मार डाला – DVK

1

सबसे आसान तरीका __parse_a_counter__ को एक सब (यानी बंद करें) वापस करने और परिणामों को वैश्विक चर में संग्रहीत करने का सबसे आसान तरीका है। उदाहरण के लिए:

use strict; 
use warnings; 
use XML::Twig; 

our @results;  # <= put results in here 

sub parse_a_counter { 
    my ($type, $index) = @_; 

    # return closure over type & index 
    return sub { 
     my ($twig, $counter) = @_; 
     my @report = $counter->children(qq{report[\@type="$type"]}); 

     for my $report (@report) { 
      my @stringSet = $report->children(qq{stringSet[\@index="$index"]}); 

      for my $stringSet (@stringSet) { 
       my @string_list = $stringSet->children_text('string'); 
       push @results, \@string_list; 
      } 
     } 
    }; 
} 

my $roots = { 'counter[@name="music"]' => 1 }; 
my $handlers = { counter => parse_a_counter("month", 4) }; 

my $twig = XML::Twig->new(
    TwigRoots => $roots,      
    TwigHandlers => $handlers, 
)->parsefile('counter_test.xml'); 

मैं निम्न XML के साथ इस परीक्षण किया (जो क्या मैं अपने उदाहरण में XML & कोड से बाहर काम कर सकता था):

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <counter name="music"> 
     <report type="week"> 
      <stringSet index="4"> 
       <string>music week 4</string> 
      </stringSet> 
     </report> 
    </counter> 
    <counter name="xmusic"> 
     <report type="month"> 
      <stringSet index="4"> 
       <string>xmusic month 4</string> 
      </stringSet> 
     </report> 
    </counter> 
    <counter name="music"> 
     <report type="month"> 
      <stringSet index="4"> 
       <string>music month 4 zz</string> 
       <string>music month 4 xx</string> 
      </stringSet> 
     </report> 
    </counter> 
</root> 

और मैं वापस मिल इस:

[ 
    [ 
     'music month 4 zz', 
     'music month 4 xx' 
    ] 
]; 

जो मैं उम्मीद कर रहा था!

4

हैंडलरों को तर्क पारित करने का सबसे आसान और सामान्य तरीका बंद करने का उपयोग करना है। यह एक बड़ा शब्द है लेकिन एक साधारण अवधारणा है: आप इस tag => sub { handler(@_, $my_arg) } और $my_arg जैसे हैंडलर को हैंडलर को पास कर दिए जाएंगे। Achieving Closure में अवधारणा के बारे में अधिक विस्तृत स्पष्टीकरण हैं।

नीचे मैं कोड कैसे लिखूंगा। मैंने तर्क प्रसंस्करण के लिए Getopt::Long का उपयोग किया, और अभिव्यक्ति में उद्धरणों का उपयोग करने में सक्षम होने के लिए, XPath अभिव्यक्ति वाले तारों के चारों ओर उद्धरणों के बजाय qq{} का उपयोग किया।

#!/usr/bin/perl 
use strict; 
use warnings; 

use XML::Twig; 

use Getopt::Long; 

# set defaults 
my $counter_name= 'music'; 
my $type= 'month'; 
my $id= 4; 

GetOptions ("name=s" => \$counter_name, 
      "type=s" => \$type, 
      "id=i" => \$id, 
      ) or die; 

my @results; 

my $twig= XML::Twig->new( 
      twig_roots => { qq{counter[\@name="$counter_name"]} 
          => sub { parse_a_counter(@_, $type, $id, \@results); } }) 
        ->parsefile('counter_test.xml'); 

print join("\n", @results), "\n"; 

sub parse_a_counter { 

    my ($twig, $counter, $type, $id, $results) = @_; 
    my @report = $counter->children(qq{report[\@type="$type"]}); 

    for my $report (@report){ 

     my @stringSet = $report->children(qq{stringSet[\@index="$id"]}); 
     for my $stringSet (@stringSet){ 

      my @string_list = $stringSet->children_text('string'); 
      push @$results, @string_list; 
     } 
    } 

    $counter->purge; # free the memory of $counter 
} 
संबंधित मुद्दे

 संबंधित मुद्दे