ノードの並び替え方法について

このQ&Aのポイント
  • javaでDOMを使ってXMLファイルを作成していますが、ノードを並び替える方法がわかりません。
  • 階層が深いとコピーが大変になるため、簡単に実現する方法はないのでしょうか?
  • ご存知の方、教えていただけると助かります!
回答を見る
  • ベストアンサー

ノードの並び替え

こんばんわyukimura1024です。 javaでDOMを使ってXMLファイルを作成していますが、ノードを並び替える方法がわかりません。 例えば以下の例ようなXMLがあり、これをA→Bのように並び替えるといったものです。 いったん取り出して作り直せばよいのですが、階層が深いとコピーが大変ですよね。 (調べたところ深いコピーはなかったです) これを簡単に実現するいい方法はないものでしょうか? ご存知の方、教えていただけると助かります!よろしくお願いします。 例) (A) <PARENT>  <CHILD1/>  <CHILD2/>  <CHILD3/> </PARENT> (B) <PARENT>  <CHILD3/>  <CHILD2/>  <CHILD1/> </PARENT>

  • XML
  • 回答数6
  • ありがとう数8

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

  • ベストアンサー
  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.6

#5>これがXSLTで簡単に変換できてしまうなら是非ご教示ください。 エラートラップを簡略していますが、こんな感じ。 XSL の部分はオンメモリということで文字列で持っていますが、 ファイルから取り込むのももちろん可。 ---------------------------------------------------------------- import java.io.*; import javax.xml.transform.*; import javax.xml.transform.dom.*; import javax.xml.transform.stream.*; import javax.xml.parsers.*; import org.w3c.dom.*; public class Sample { public static void main(String args[]) throws Exception{ String xsl= //"<?xml version='1.0' encoding='Shift_JIS' ?>"+ "<xsl:stylesheet version='1.0' "+ "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>"+ "<xsl:output method='xml' version='1.0' encoding='Shift_JIS' indent='yes' />"+ "<xsl:template match='/ROOT'>"+ "<xsl:element name='ROOT'>"+ "<xsl:apply-templates select='PARENT1' />"+ "<xsl:copy-of select='PARENT2' />"+ //そのまま "<xsl:apply-templates select='PARENT3' />"+ "</xsl:element>"+ "</xsl:template>"+ "<xsl:template match='PARENT1'>"+ "<xsl:element name='PARENT1'>"+ "<xsl:copy-of select='CHILD_HEAD' />"+ "<xsl:copy-of select='CHILD_PROP' />"+ "<xsl:copy-of select='CHILD_END' />"+ "</xsl:element>"+ "</xsl:template>"+ "<xsl:template match='PARENT3'>"+ "<xsl:element name='PARENT3'>"+ "<xsl:copy-of select='CHILD_HEAD' />"+ "<xsl:copy-of select='CHILD_END' />"+ "<xsl:copy-of select='DETAILS_A' />"+ "</xsl:element>"+ "</xsl:template>"+ "</xsl:stylesheet>"; DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = dbfactory.newDocumentBuilder(); Document doc = builder.parse(new File("parent.xml"));//ファイルからDOMを作る、実際は作ってあるはずなのでこの部分は必要ない DOMSource in = new DOMSource(doc); StreamSource ss = new StreamSource(new StringReader(xsl)); StreamResult out = new StreamResult(new File("result.xml")); //ファイルに書き出す TransformerFactory tff = TransformerFactory.newInstance(); Transformer tf = tff.newTransformer(ss); tf.transform(in,out); } }

yukimura1024
質問者

お礼

BLUEPIXYさんこんにちは! 何度も丁寧に回答していただきありがとうございました(^^ おかげで問題も解決しました。 XSLTは今まで使ったことがなかったので、大変勉強になりました。

yukimura1024
質問者

補足

BLUEPIXYさん。おはようございます。 ここまでソースを書いていただいてありがとうございます。 早速実際に使ってみたいと思います。 のちほど結果報告しますね。

その他の回答 (5)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.5

>実際はそうではないです。 そうですか、また、具体的なコードを書かなくて良かったです。 次から次へと、あれは、(実際とは)違ってるとか言われると萎えるし・ #3(と#1)でできるということは、おわかりになったのでしょうか? まさに、DOM(とか)を変換するというものですけど・ XSLTがわからないとどう書いていいのかわからんかもしれませんね。 #1を見て貰うと判るかもしれませんが、 マッチしたところを、こういう構成に変更するというのが基本的なテンプレートの書き方なので、直下のノードであろうがあるまいが、 ここで、これにマッチしたものをこれに置き換えるという記述ができます。 結局実際と違うということになってしまうので、質問で書かれた構成についてサンプル(XLST)を書いてもムダになってしまうので、 もし、問題がなければ、実際のこういう構成のものをこういう構成にしたいというものを補足してもらうのが簡単だと思います。

yukimura1024
質問者

補足

BLUEPIXYさん、こんばんは。何度もすみません。 実際の構成はノード名は違いますが以下のものになります。 (変換前) <ROOT>  <PARENT1>   <CHILD_PROP/>   <CHILD_END/>   <CHILD_HEAD/>  </PARENT1>  <PARENT2>   <CHILD_PROP/>   <CHILD_END/>  </PARENT2>  <PARENT3>   <CHILD_END/>    <DETAILS_A/>   <CHILD_HEAD/>  </PARENT3> </ROOT> (変換後) <ROOT>  <PARENT1>   <CHILD_HEAD/>   <CHILD_PROP/>   <CHILD_END/>  </PARENT1>  <PARENT2>   <CHILD_PROP/>   <CHILD_END/>  </PARENT2>  <PARENT3>   <CHILD_HEAD/>   <CHILD_END/>    <DETAILS_A/>  </PARENT3> </ROOT> このようにROOT/PARENTxx/以下のノードを、CHILD_HEAD→CHILD_PROP→CHILD_ENDの順に並び替えたいというものです。 (注意点) 1.PARENTxx以下にHEAD,PROP,ENDと3つ揃っていない場合もある。 2.CHILD_xx以下にさらにノードがある場合もある。 うーん。これでうまく伝わるでしょうか。これがXSLTで簡単に変換できてしまうなら是非ご教示ください。よろしくお願いします。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

ちょっと伺いたいのですが、 DOMツリーの中で、ルート直下のノードを入替てもあまり意味が無いような気がするのですが、 今回の目的というのは、XMLソースファイルを別の変換したXMLファイルにするということなのでしょうか?

yukimura1024
質問者

補足

BLUEPIXYさんこんばんは(^^ 例として書いたものはルート直下ですが、実際はそうではないです。そのへんは関係ないかなと思いシンプルな例を書いてしまいました。 今回この質問をした背景としましては以下の4点です。 1.JavaコードでXMLファイルを作成する 2.すでにロジックはほぼ完成している 3.順番は関係ない→やっぱりちゃんと順番を決めると仕様が変わった(泣 4.ロジックを変えるのが大変 というわけでいったん作ったDOMツリーを簡単に並び替えられる方法を探していました。 なので「XMLソースファイルを別の変換したXMLファイルにする」ということでほぼ合っていると思います。 ※実際はXMLファイルを読み込んで変換するのではなく、何もないところから作ったDOMツリーをファイル出力する前にもう一度組み立てなおす、といった感じです。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

>参考になるサイトなどありますでしょうか。 http://www.asahi-net.or.jp/~ps8a-okzk/xml/java_examples/transform.html のような感じですね。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

#1です。 >今回はソートではなく任意の並び替えが目的です。 ノード名で降順にソートしたいのだと思っていました。 >XSLは使ったことがないのですが、JAVAコードで書けるものでしょうか? TransformerFactory を使えば、XSLによる変換が可能です。 ソートとかしない単純な並び替えであれば、 XPath で指定したノードを xsl:copy-of を望む順番に置いて並び替えるだけなので、 静的なXSLでなくても、動的にXSLを作ることも簡単だと思います。

yukimura1024
質問者

補足

BLUEPIXYさん回答ありがとうございます。 なるほど、動的に内部でXSLを作り出してそれを使うということですか。それなら外部にファイルを用意しなくても良いのでよさそうですね。 XSL自体まったく使ったことがなく、変換のやり方が想像できないのですが今回の問題でどこか参考になるサイトなどありますでしょうか。 実際のコードなど書いてあるととても助かります(^^;

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.1

下記のようなXSLを作成して、適用する ---------------------------------------------------------------- <?xml version="1.0" encoding="Shift_JIS"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" version="1.0" encoding="Shift_JIS" indent="yes" /> <xsl:template match="/PARENT"> <xsl:element name="PARENT"> <xsl:for-each select="*"> <xsl:sort select="name(.)" data-type="text" order="descending"/> <xsl:copy-of select="." /> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet>

yukimura1024
質問者

補足

すみません。XSLは使ったことがないのですが、JAVAコードで書けるものでしょうか? それと今回はソートではなく任意の並び替えが目的です。 1,2,3と単純に書いたのでソートでOKっぽく見えてしまいますね。。。(^^;)

関連するQ&A

  • XMLの子要素追加の順番について

    PHP板が見つからなかったのでここに・・・ $dom = new DOMDocument(); $dom->formatOutput = true; $dom->load("test.xml"); で読み込み $child = $parent->appendChild($dom->createElement('child')); $child->appendChild($dom->createCDATASection($_POST['post'])); このように追加を行った場合 XMLには、追加されますが上から順番に追加されていきます。 <parent> <child>追加1</child> <child>追加2</child> <child>追加3</child> <parent> 下記のように先頭に追加する場合はどのようにすればいいのでしょうか? <parent> <child>追加3</child> <child>追加2</child> <child>追加1</child> <parent> ご回答のほどよろしくお願いします。

    • ベストアンサー
    • PHP
  • PHP5 domDocumentで簡単に深いノードを取得する。但し、SimpleXMLを使わない

    環境はPHP5です。 SimpleXML(simplexml_load_file)を使わない事情がありまして、domDocumentを使っています。 $dom = new domDocument(); $dom->load("example.xml"); $root = $dom->documentElement; foreach($root->childNodes as $elems) { if ($elems->nodeType == XML_ELEMENT_NODE && $elems->nodeName == "Items") { ... ... ... 例えば以下のようなXMLの場合、<D2>のyyyyyを取得する為に上のプログラムだと、 foreach, ifのネストが深くなり、階層が深くなるにつれてプログラムの記述も増えて 非常に面倒ですが、$rootを使って、yyyyyの値を1行程度で取得する方法ないのでしょうか? <A> <Items> <B1></B1> <B2> <C> <D1>xxxxx</D1> <D2>yyyyy</D2> </C> </B2> <B3></B3> </Items> </A>

    • ベストアンサー
    • PHP
  • 既存のXMLを別のXMLの要素として追加する方法

    JavaでDOMを使用して、既に作成してあるXMLを別のXMLの要素として追加しようと思っているのですが、なかなか上手くいかないので投稿いたしました。 具体的に以下のような既存のXMLファイルがあると仮定して、 <?xml version="1.0" encoding="UTF-8"?> <a> <b>0</b> <c>1</c> <d>2</d> </a> 上記のXMLの親ノード(逆に言えば、このXMLの子ノードとして上記XMLを追加)にあたるXMLは以下のようになっています。 <?xml version="1.0" encoding="UTF-8"?> <A> </A> そして<A>と</A>の間に既存のXMLを追加して、 <?xml version="1.0" encoding="UTF-8"?> <A> <a> <b>0</b> <c>1</c> <d>2</d> </a> </A> のようにしたいと考えています。 よろしくお願いします。

    • ベストアンサー
    • Java
  • ルート要素ノードが2個ある場合?

    xmlからxmlへの変換時に出るエラーについての質問です。 元データとなるxmlが下のような構造をしています。 ルート要素の要素ノードが2つあるものです。 <A1>   <B1>aaa</B1>   <B2>     <C1>bbb</C1>   </B2> </A1> <A2>ccc</A2> これをxsltで違う形のxmlに変換するのですが、変換中にエラーが出てしまいます。 (使用しているのはApache xalanです) 現在は元データに、<root>ノードを最上位に加えることにより、変換しているのですが、他の方法で対処できないでしょうか? よろしくお願いいたします。

    • ベストアンサー
    • XML
  • 何番目のParentNodeのChildNodeかわかりません。

    C#のDOMを使ってXMLを読み取るときに、 XmlNodeListから取得できますが、 ParentNodeが同じものがある場合、(下記) 何番目のParentNodeのChildNodeかわかりません。 <parent> <child>1</child> <parent> <child>2</child> <parent> <child>3</child> ChildNode.Countでの個数が3つというのは取得できますが、 何回目のParentNodeのChildなのかを調べることは可能でしょうか?

    • ベストアンサー
    • XML
  • domでのXML作成について

    PHP4.2のdomを使い、下記のようなXMLを作成したいです。 しかし、Itemのノードに対して、NUMBERとNAMEという子ノードを2つつけるやり方が分からず困っています。 PHPは書いて見たのですが、上手くいっていません。 教えていただけると助かります。 宜しくお願いします。 【作成したいXML】 <Response> <Items> <Item> <NUMBER>47</NUMBER> <NAME>沖縄県</NAME> </Item> </Items> </Response> 【PHP】 $dom = domxml_new_doc("1.0"); $Response = $dom->create_element("Response"); $root = $dom->append_child($Response); $Items = $dom->create_element("Items"); $Item = $dom->create_element("Item"); $NUMBER = $dom->create_element("NAME"); $text1 = $dom->create_text_node("47"); $NUMBER->append_child($text1); $NAME = $dom->create_element("NAME"); $text2 = $dom->create_text_node("沖縄"); $NAME->append_child($text2); $Item->append_child($NAME); $Items->append_child($Item); $root->append_child($Items);

    • ベストアンサー
    • PHP
  • XSLTによるノードの抽出の際に親のnamespaceで子ノードのnamespaceが上書きされないようにするには?

    下記のようなXMLに <?xml version="1.0" encoding="EUC-JP"?> <parent xmlns:xhtml="http://parent"> <child id="A1"> <taroh xmlns="http://child"> <age>10</age> </taroh> </child> </parant> 下記のようなXSLTを適用した場合、 <?xml version="1.0" encoding="EUC-JP"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" > <xsl:output method="xml"/> <xsl:template match="text()|@*"> </xsl:template> <xsl:template match="node()[@id='A1']"> <xsl:copy-of select="./node()"/> </xsl:template> </xsl:stylesheet> 通常下記のような結果となりますが、 <?xml version="1.0" encoding="EUC-JP"?> <taroh xmlns="http://parent"> <age>10</age> </taroh> namespaceを変更させずに、下記のような結果を 得るためにはどのようにすればよいでしょうか? <?xml version="1.0" encoding="EUC-JP"?> <taroh xmlns="http://child"> <age>10</age> </taroh> 抽出には javax.xml.transform.Transformerを用いています。 どうか、よろしくお願いします。

    • 締切済み
    • XML
  • PHP5 XML 既存属性ノードから属性を追加する方法

    お世話になっています。 現在PHP5を勉強中のものです。 XMLとの連携で下記のようなことを行いたいと思っています。 ・XMLを用いてアクセスログ(日計)を作ってみる。 ・(1)→(2)のように日々属性ノードが追加される。 【既存XML】 (1)<<AcLog.xml>>※2007/02/05 現在 ----------------------------------------------------- <?xml version="1.0" encoding="utf-8"?> <parent> <Accsess id="1"> <Date>20070205</Date> <Count>10</Count> </Accsess> </parent> (2)<<AcLog.xml>>※2007/02/06 現在 ----------------------------------------------------- <?xml version="1.0" encoding="utf-8"?> <parent> <Accsess id="1"> <Date>20070205</Date> <Count>10</Count> </Accsess> <Accsess id="2"> <Date>20070206</Date> <Count>1</Count> </Accsess> </parent> ----------------------------------------------------- 現在様々な参考書やネットサンプルなど見てはいるのですが、 どうしても<parent>の外で作成されてしまったりなど、 良い結果を生んでいません。 こんなことで質問するのはどうかとも思っておりますが、 サンプルサイトなどございましたらご教授ください。 よろしくお願いします。

    • 締切済み
    • PHP
  • xmlファイルが生成されない

    <?php //DomDocumentを呼び出す $dom = new DomDocument('1.0','UTF-8'); //要素ノード[document]を追加 $document = $dom->appendChild($dom->createElement('document')); //新しい要素をdocumentの子要素として挿入する $document->appendChild($dom->createElement('name','名前です')); $document->appendChild($dom->createElement('text','テキストです。')); //字下げや空白を考慮してきれいに整形した出力を行う $dom->formatOutput = true; //同階層にtest.xmlとして保存 $dom->save('test.xml'); //出力 echo $dom->saveXML(); ?> のように、同じディレクトリ内にXMLファイルを生成するphpプログラムを作成してみたのですが、 ブラウザからこのPHPファイルにアクセスしてもXMLファイルが作られません。どうすれば良いのでしょうか。 なにかphp,apache等の設定をしてないからでしょうか。 よろしくお願いします。

    • 締切済み
    • PHP
  • XMLファイルの読み方

    以下の様なXMLファイルがあるとします。 "groupノード(?)のアトリビュートであるgrpIDとnumStdGrpの値を取得したいです。 JavaでDOMパーサーを使うことに限定します。 <?xml version="1.0" encoding="UTF-8"?> <dataHeader <numStudent>150</numStudent> <dataMain <band name="B1"> <group grpID="1" numStdGrp="15"/> </band> <band name="B2"> <group grpID="2" numStdGrp="10"/> </band> </dataMain> </dataHeader> 自分では試して見たのは以下まで。 File fXmlFile = new File("C:\XMLファイル名"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(fXmlFile); doc.getDocumentElement().normalize(); (1)numStudentとdataMainノードまでは簡単: 例) NodeList nListDM = doc.getElementsByTagName("dataMain"); 上記からnListDM.item(0)してノード取得できて、getNodeName()で名前表示する。 (2)bandノード(?)もgetElementsByTagNameで取れます。 NodeList nListBand = doc.getElementsByTagName("band"); このノードリストの長さは2です。それぞれ、アトリビュート「name」の値(B1, B2)は以下の様にして取れます。 Node nNodeBand = nListBand.item(0); Element bElement = (Element) nNodeBand; して、bElement.getAttribute("name")。 問題はこの以降。 初めに書きましたように、 groupノード(?)のアトリビュートであるgrpIDとnumStdGrpの値どうやって取得するのでしょうか? getElementsByTagName(group)はだめです。どのbandのgroupか、区別できないので。 Java+XMLに詳しい方、教えてください。 よろしくお願いします。

    • ベストアンサー
    • Java

専門家に質問してみよう