XML::XPathでXMLを修正して出力する方法

このQ&Aのポイント
  • XML::XPathを使用してXMLを修正する際に、修正後のXMLを出力する方法について教えてください。
  • 質問者はXML::XPathを使用してXMLを修正し、修正後のXMLをテキストとして出力したいと考えています。
  • 具体的には、最後の`print $xp`の部分で修正後のXMLを出力する方法を知りたいです。
回答を見る
  • ベストアンサー

XML::XPath でXMLを修正して出力するには?

XML::XPath を使って以下のようなソースを書きましたが、出力の方法がわかりません。 ++++++++++++++++ use strict; use XML::XPath; my $filename = "test.html"; my $xp = XML::XPath->new(filename=>$filename); my @nodeset = $xp->findnodes("//div[attribute::class='center']//img[attribute::class='right'"); for my $node ( @nodeset ){ print $node->removeAttribute('class'), "\n"; } print $xp; 1; ++++++++++++++++++++++++++++ 最後の print $xp のところで、修正後のXMLを出力したいです。 修正後のXMLをテキストとして出力(変数に入れるでも、標準出力でも)するには、どうすればよいのでしょうか?

  • Perl
  • 回答数5
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
回答No.5

これが最善の方法なのかは分かりませんが、分かる範囲でお答えします。 ANo.2の別解をもう一度引用します。 for my $div ($xml->findnodes('//div[@class="center"]')) { for my $img ($div->findnodes('//img[@class="right"')) { $img->removeAttribute('class'); } print $div->toString, "\n"; } これを応用すると、以下のようなコードが考えられます。 for my $root ($xml->findnodes('/')) { for my $img ($root->findnodes('//img[@class="right"]')) { $img->removeAttribute('class'); } print $root->toString, "\n"; } つまりルート要素から順にXML::XPathに解析させるというものです。 動くかどうかは分かりません。すみません。

yocean1201
質問者

お礼

root ノードを取得して、それを toString するという方法で うまくいきました。 ありがとうございました!!

その他の回答 (4)

回答No.4

ANo.3ではなくANo.2の間違いです。 度々すみません。

回答No.3

ANo.3で書くのを忘れてしまいましたが、 my $xml = XML::XPath->new(filename => 'test.html'); を前提としたコードです。

yocean1201
質問者

お礼

No.2 のお礼での訂正です。 ×>変更した後の前文を出力させたいのですが、そんな方法はありますでしょうか? ○>変更した後の全文を出力させたいのですが、そんな方法はありますでしょうか?

回答No.2

例えばこんなのはどうでしょうか。 for my $node ($xml->findnodes('//div[@class="center"]//img[@class="right"]')) { $node->removeAttribute('class'); print $node->toString, "\n"; } あるいは次のような別解も。 for my $div ($xml->findnodes('//div[@class="center"]')) { for my $img ($div->findnodes('//img[@class="right"')) { $img->removeAttribute('class'); } print $div->toString, "\n"; }

yocean1201
質問者

お礼

> おそらく、$xp->findnodes() や $node->removeAttribute() などとしても、$xp 自体には変更が及ばないのではないでしょうか。 なんとなくそんな予想もしてはいたのですが、やっぱりそうなのでしょうか・・・。 $nodeset が $xp のもつオブジェクトの集合として渡されるなら、いけるかなーと思ったのですが。 いただいた解決例だと、該当する部分のタグしか出力しないですよね。 変更した後の前文を出力させたいのですが、そんな方法はありますでしょうか?

回答No.1

これは勘による、全く当てにならない回答であることをお断りしておきます。 おそらく、$xp->findnodes() や $node->removeAttribute() などとしても、$xp 自体には変更が及ばないのではないでしょうか。 つまり最後に $xp を出力したのではもう遅いということです。 多分 for 文の中で、$node に対してループが回るたびに出力処理を行うか、もしくは: my $result; for my $node (@nodeset) { #... $result .= $node->whatever(); } print $result; のようにして、別な変数に修正結果をためておき、最後に出力するという形になるのではないでしょうか。 私も日々XML::XPathを扱っていますが、修正→出力目的で使用したことはないので、アドバイスはここまでとなります。

関連するQ&A

  • PerlによるXMLファイルの解析&出力

    XMLファイルで以下のようなXMLファイルから、 <?xml version="1.0" encoding="Shift_JIS"?> <class3> <Personal> <No>1</No> <Name>相上男</Name> <phone>00-0000</phone> </Personal> <Personal> <No>2</No> <Name>柿句毛子</Name> <phone>11-1111</phone> </Personal> </class3> perlでNameの部分のタグだけ抜き出しXMLファイルに出力するプログラムを組み立てたいです。自分でも以下のようなプログラムを組み立てたのですが、 #!/usr/bin/perl use strict; use Encode; use XML::XPath; use XML::XPath::XMLParser; # 書き込み用にファイルを開く open( OUTPUTFILE, ">Output2.xml" ); # 標準出力に書き出し print &xml_xpath; # ファイルを出力先に設定 select( OUTPUTFILE ); # 出力先を元に戻す select( STDOUT ); # ファイルを閉じる close( OUTPUTFILE ); sub xml_xpath{ my $file = "class3.xml"; my $xp = XML::XPath->new(filename => $file); foreach my $node( $xp->find('/class3/Personal/Name')->get_nodelist){ print Encode::encode("shift_jis", $node )."\n"; } } XML::XPath::Node::Element=REF(0x1036c58c) XML::XPath::Node::Element=REF(0x1036cb8c) と、出てくるだけで動きません。ほとんど初心者なのでまったく見当違いのプログラムを組み立てているかもしれませんが、よろしくおねがいします。

  • XML::XPathを使う

    エラーがでて期待する出力が出ず困っています。 ファイル名とXPathのコマンドライン引数をとり、 指定されたパスに一致するノードを出力するものです。 (参考書の写しなので、記述ミスはないと思います。) ■grabber.pl use XML::XPath; use XML::XPath::XMLParser; my $xpath = XML::XPath->new( filename => shift @ARGV ); my $nodeset = $xpath->find( shift @ARGV ); foreach my $node ( nodeset->get_nodelist ) { print XML::XPath::XMLParser::as_string( $node ) . "\n"; } コマンドラインに入力しているものは、 perl grabber.pl data.xml "/inventory/category/item/name" ■data.xml <?xml version="1.0"?> <inventory date="2001"> <category> <item id="2"> <name>aaaa</name> </item> </category> </inventory> です。 perl grabber.pl data.xml "/inventory/category/item/name" としても、下記にエラーが出ます。 Can't locate object method "get_nodelist" via package "nodeset" (perhaps you for got to load "nodeset"?) at grabber.pl line 5. いろいろ試してみたり調べたのですが、 行き詰ってしまいました。 期待する出力は"<name>aaaa</name>"なのですが・・・ どなたかこのエラーの原因がおわかりになるかた いらっしゃいますでしょうか。 環境は以下になります。 ・windowsxp ・activePerl モジュールのインストール済み ・XML-XPath ・XML-Parser 以上です。

    • ベストアンサー
    • Perl
  • XML::XPath -- 追加したノードが見付からない

    XMLのテンプレートを既存のXMLに追加したのですが、 その後 findnodes() で検索しても合致しません。 XML::XPath::Node::Element->new() を使って作成したものは 合致してくれます。 XML::XPath::XMLParser でパースしたものを追加して findnodes() で合致させるにはどのようにしたらよいのでしょうか。 ------------------------------- use XML::XPath; #### 元のXML my $xmldata = <<EOM; <?xml version="1.0" encoding="UTF-8" ?> <list>   <item>orange</item>   <item>apple</item>   <item>lemon</item> </list> EOM ### 追加するXMLのテンプレート my $xmlappend = <<EOM;   <item>pine</item> EOM ## 追加先ノードを取り出す my $xml = XML::XPath->new( xml=>$xmldata ); my ($list) = $xml->findnodes('/list'); ## 追加用XMLを作成して追加 my $append = XML::XPath::XMLParser->new( xml=>$xmlappend )->parse; $list->appendChild( $append ); ## もういっこ追加。こちらはこの場で作る $newnode = XML::XPath::Node::Element->new('item'); $newtext = XML::XPath::Node::Text->new('banana'); $newnode->appendChild( $newtext ); $list->appendChild( $newnode ); ## 現状確認 → pine は入っていた print $list->toString."\n"; ## item一覧を取得 @nodes = $xml->findnodes('/list/item'); ## 一覧を出力 → 追加した pine が出力されない。 bananaはある。 map{ print $_->toString."\n" } @nodes;

    • ベストアンサー
    • Perl
  • XML::XPathでのfor文の記述

    たびたびお世話になります。よろしくお願いいたします。 perlでXML文書をHTMLへ変換しています。 ---------------------------------------- <!-- file.xml --> <root> <jouhou> <mei> <toushu>あ</toushu> <toushu>い</toushu> <toushu>う</toushu> </mei> <mei> <toushu>え</toushu> <toushu>お</toushu> <toushu>か</toushu> </mei> </jouhou> </root> ---------------------------------------- このようなXMLの場合に、XML::XPathで「あ」と「え」などの最初に来る<toushu>取りたいのですが 日によって<mei>の数が異なるため、<mei>の数を取得してその数でforをすることにしました。 が、うまくいきません。 my $xp = new XML::XPath( filename => "./file.xml" ); for(my $j=1;$j<=$xp->findvalue("count(//jouhou/mei/toushu)");$j++){ print $j; #←ここでは1と2が出ます。 print $xpath->find('//jouhou/mei[$j]/toushu')->get_node(1)->string_value; } このままでは全く出なく、["$j"]とすると、出るには出るのですが「あ」が2回出てしまいます。 書き方が違うと思うのですが、()でくくってみても出ません。 ちなみに print $xpath->find('//jouhou/mei[1]/toushu')->get_node($j)->string_value; だと、ちゃんと「あ」と「い」が出ました…。 もし、お分かりになれば教えていただきたいです。 お手数をおかけしますが、よろしくお願いいたします。

    • ベストアンサー
    • Perl
  • ->の意味

    よく->といったものが、 参考スクリプトなどをみていると、 でてくるのですが、いまいちどう 解釈してよいのやらわかりません。 調べてもなかなかみつからず、質問させていただきます。 use XML::XPath; use XML::XPath::XMLParser; my $xpath = XML::XPath->new( filename => shift @ARGV ); my $nodeset = $xpath->find( shift @ARGV ); foreach my $node ( $nodeset->get_nodelist ) { print XML::XPath::XMLParser::as_string( $node ) . "\n"; } XML::XPath->new( filename => shift @ARGV );とか $xpath->find( shift @ARGV );とか $nodeset->get_nodelistは どういった理解をすればよいのでしょうか。 教えていただけますでしょうか。

    • ベストアンサー
    • Perl
  • XML::DOM / XML::XPathでソート

    XML::DOMで効率的なソートの方法はどんなものがありますでしょうか。 一応動くものは作れたのですが、効率的とは言い難く、しかも ソート項目が一意のデータでないといけないという欠点があります。 ############################################### use XML::DOM::XPath; my $xml = <<EOM; <?xml version="1.0" encoding="UTF-8" ?> <list> <item id="10">Apple</item> <item id="5">Orange</item> <item id="20">Melon</item> </list> EOM my $parser = XML::DOM::Parser->new(); my $doc = $parser->parse( $xml ); ## <item>タグの一覧を作成 my @list = $doc->findnodes('/list/item'); ## <item>タグ id属性一覧を作成 my @idlist = map{ $_->getAttribute("id") } @list; ## id属性順にソート foreach my $id ( sort{ $a<=>$b } @idlist ){ ## id属性値を指定してノードリストを取得 my @item = $doc->findnodes('/list/item[@id='.$id.']'); ## idは一意なのでリストの先頭で固定 print $item[0]->getAttribute('id')."\n"; print $item[0]->getFirstChild->getNodeValue."\n"; } ############################################### ハッシュなら sort{ $hoe{$b} <=> $hoe{$a} } keys %hoe といった方法があるのですが、XML::DOMの場合は同じようにいきません。 良い方法がありましたらお願いします。

    • ベストアンサー
    • Perl
  • XMLとの連携でノードの長さを取り出す方法

    PHP--------------------------------------------- $xpath = "/qq:album/img"; $xpath = mb_convert_encoding($xpath,"UTF-8","SJIS"); $x_array = $ctx->xpath_eval($xpath); $title_element = $x_array->nodeset[0]; $title = $title_element->get_attribute("title"); $title = mb_convert_encoding($title,"SJIS","UTF-8"); XML---------------------------------------------- <?xml version="1.0" encoding="EUC-JP"?> <qq:album xmlns:qq="www.phpdom.com"> <img title="ABC"> <img title="DEF"> <img title="GHI"> <img title="JKL"> </qq:album> こんにちは。 http://www.geocities.jp/xmlfirststep/dom/dom4.html のサイトを参考に、上のようなスクリプトを書きました。albumという名の親ノードの下にあるimgノードの要素titleを抜き出すものです。このimgノードをXMLで複数つくり、phpでその長さを自動で返してもらおうと思ったのですがそのやり方がわかりません。 色々なサイトを回りましたが、キーワード「length」で探してもそれらしき情報がまったく見つかりません。 どうすればノードの長さを返してもらえるのでしょうか?

    • ベストアンサー
    • PHP
  • Rubyにおける、XPathの関数「text()="x"」への変数の使

    Rubyにおける、XPathの関数「text()="x"」への変数の使用方法 お世話になります。 RubyにてXPathの関数「text()="x"」"x"の部分に変数を使用したいと思い、コードを作成しています。 text() 関数のところで困っています。 例えば <?xml version="1.0" encoding="UTF-16"?> <NameRoot> <Text> <Name>あああああ</Name> <No>001</No> </Text> <Text> <Name>いいいいい</Name> <No>002</No> </Text> <Text> <Name>ううううう</Name> <No>003</No> </Text> </NameRoot> の内容のファイルを読み込み、その中から該当するNoに相当するNameを取得しようと しています。 で、書いたのが下記のような内容なのですが、gettestクラスのgetNameメソッドにて コメントアウトしてある行であれば、決め打ちでNo="001"の物を取ってこれるのですが、 ここに引数として渡されたローカル変数の、idを使用しようとするとnode変数にNilClass が返ってきて取得できません。 文字列リテラルを色々調べてみたのですが、どうも上手く行かず困っています。 他愛も無い質問かもしれませんが、大変困っています。 どなたか知恵をお貸しくださいますようお願い致します。 class gettest def getName(id) #↓これがきちんと動きません node = REXML::XPath.first(@masterdata, '//NameRoot/Text/No[text()="#{id}")]') #↓こちらは当然ながら動きます # node = REXML::XPath.first(@masterdata, '//NameRoot/Text/No[text()="001"]') path = (node.xpath + "/../Name") @name = @masterdata.elements[path].text() end end class main def edit @mastername = "" @mastername = @master.getName("001") print @mastername end end

    • ベストアンサー
    • Ruby
  • strict.pmはどこにありますか?

    ローカル環境ではstrictを ダウンロードしていれた記憶もないので 標準モジュール かな?っと思っていたのですが さくらインターネットを借りようとしているのですが use strict; を書くとInternal Server Error になるんです。 XML::XPath; など ほかのモジュールは、http://theoryx5.uwinnipeg.ca/ppms/ からダウンロードして use lib ' で使えるようにしたのですが、 strictだけ みつからないので 動作確認して使えないんです。 strict.pmを配布しているサイトをご存じでしたら 教えてください。

    • ベストアンサー
    • Perl
  • Load出来ないXMLファイル

    いつもお世話になっております。 標題の件なのですが、VB.NETでXMLファイルから設定情報(Oracleのユーザー名やパスワード等)を取得するプログラムを作成しております。 以下がそのソースコードになります。 ※VB.NET初心者なので、ネットにあったサンプルコードを参考にしました。 --------------------------------------------------   Public Function Setting_init() As Boolean     Dim xmlDoc As New DOMDocument30     Dim Node As IXMLDOMNode     Dim myErr     Dim FileName As String     FileName = "ini.xml"     Const PATH_DTS = "//Settings/Database/DataSource"     Const PATH_UID = "//Settings/Database/UserId"     Const PATH_PSW = "//Settings/Database/Password"     Const PATH_FRM = "//Settings/Path/Form"     Const PATH_OUT = "//Settings/Path/Output"     xmlDoc.async = False     xmlDoc.resolveExternals = False     xmlDoc.load(FileName)          If (xmlDoc.parseError.errorCode <> 0) Then       myErr = xmlDoc.parseError       Setting_init = False     Else       xmlDoc.setProperty("SelectionLanguage", "XPath")       Node = xmlDoc.selectSingleNode(PATH_DTS)       G_DataSorce = Node.text       Node = xmlDoc.selectSingleNode(PATH_UID)       G_UsrId = Node.text       Node = xmlDoc.selectSingleNode(PATH_PSW)       G_PassWord = Node.text       Node = xmlDoc.selectSingleNode(PATH_FRM)       G_FormPath = Node.text       Node = xmlDoc.selectSingleNode(PATH_OUT)       G_OutPath = Node.text       Setting_init = True     End If   End Function -------------------------------------------------- ちなみにXMLファイルの内容は -------------------------------------------------- <?xml version="1.0" encoding="utf-8"?> <Settings>  <Database>   <DataSource>Oracleサーバー名</DataSource>   <UserId>ユーザー名</UserId>   <Password>パスワード</Password>  </Database>  <Path>   <Form>フォームが存在するフォルダパス</Form>   <Output>ファイルを出力するフォルダパス</Output>  </Path> </Settings> -------------------------------------------------- となっております。 お客様の環境で実行したら、このプログラムのxmlDoc.load(FileName)の箇所でエラーが出ました。 読み取るXMLファイル内の漢字を除いたら実行できたみたいなのですが、 開発環境ではXMLファイルに漢字を含んでいても問題なくload出来るのです。 端末に依存するのでしょうか? それともこの文字があったらダメというのがあるのでしょうか? 何か情報があればご教示願います。 よろしくお願い致します。

専門家に質問してみよう