JavaScript(正確にはJSFL)で質問です。

(注意:この質問ではTab空白が使えないみたいなので、インデントは全角スペースにしてます。貼り付ける場合には注意してください)

=========================================================================
var arr = ["test/test1",
      "名称未設定フォルダ 2/名称未設定フォルダ 1",
      "名称未設定フォルダ 2/名称未設定フォルダ 4/名称未設定フォルダ 5"];
=========================================================================

上記の配列の情報を使って、

=========================================================================
<node label="test">
  <node label="test1" />
</node>
<node label="名称未設定フォルダ 2">
  <node label="名称未設定フォルダ 1" />
  <node label="名称未設定フォルダ 4">
    <node label="名称未設定フォルダ 5" />
  </node>
</node>
=========================================================================

この文字列を作成したいのですが、なんとかならないでしょうか?
"/"がフォルダの区切り文字で、フォルダ構成をXMLで吐き出したいのです。

長時間頑張って見たんですが、どうにも自分では思いつかないので、是非、皆さんの知恵を拝借したく思います。
よろしくお願い致します。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2009/08/16 23:18:43
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:GoldenDawn No.4

回答回数426ベストアンサー獲得回数81

ポイント28pt

sortFunc の仕様が不明なので無視して動かしたら data 属性がおかしかったので sortFunc なしでの記述をば。

function putXML(v) {
  var l = [] ;
  var r = '' ;

  for (var i = 0; i < v.length; ++i) {
    var b = v[i].split('/') ;
    for (var n = 0; n < b.length; ++n) {
      var e = 'l["' + b.slice(0, n+1).join('"]["') + '"]' ;
      eval('if (' + e + ' == undefined) ' + e + '=[];') ;
    }
  }

  function digg(i, d, dt) {
    ++d ;
    var n = 0 ;
    for (var a in i) {
      if (n++ == 0 && d > 1) r += '>\n' ;
      r += Array(d).join('  ') + '<node label="' + a + '" data="' + dt + a + '"' ;
      digg(i[a], d, dt + a +'/') ;
    }
    --d ;
    if (n == 0) r += ' />\n' ;
    else if (d > 0) r += Array(d).join('  ') + '</node>\n' ;
  }

  digg(l, 0, '') ;

  return r ;
}
id:kreuz2nd

早っ!(笑

いやー・・・言葉が出ないというか、参りました。(汗

なるほど、パラメータを増やして、フォルダ名を再帰で渡すとは・・・まったく思いつきませんでした。よくよく考えれば、その考え方のほうが普通に出てくるはずなのに全く出てこなかったのが悔しいですねぇ。・・・この悔しさをバネに頑張ります。

sortFuncは消し忘れでした。(汗

本当に、本当にありがとうございました。凄く助かりました。また機会がありましたらよろしくお願いします!

2009/08/16 23:17:39

その他の回答3件)

id:GoldenDawn No.1

回答回数426ベストアンサー獲得回数81

ポイント23pt

普通に HTML + JavaScript ですが。

<html>
  <head>
    <script type="text/javascript">
      var arr = ["test/test1",
                 "名称未設定フォルダ 2/名称未設定フォルダ 1",
                 "名称未設定フォルダ 2/名称未設定フォルダ 4/名称未設定フォルダ 5"] ;

      function putXML(v) {
        var l = [] ;
        var r = '' ;

        for (var i = 0; i < v.length; ++i) {
          var b = v[i].split('/') ;
          for (var n = 0; n < b.length; ++n) {
            var e = 'l' ;
            for (var m = 0; m < n+1; ++m) e += '["' + b[m] +'"]' ;
            e = 'if (' + e + ' == undefined) ' + e + '=[];\n' ;
            if (m > 0) eval(e) ;
          }
        }

        var d = 0 ;
        function digg(i) {
          ++d ;
          var n = 0 ;
          for (a in i) {
            if (n == 0) r += '>\n' ;
            ++n ;
            r += Array(d+1).join('  ') + '<node label="' + a + '"';
            digg(i[a]) ;
          }
          --d ;
          if (n == 0) {
            r += ' />\n' ;
            return ;
          }
          r += Array(d+1).join('  ') + '</node>\n' ;
        }

        for (a in l) {
          r += '<node label="'+ a + '"' ;
          if (l[a] != []) digg(l[a]) ;
        }

        return r ;
      }

      onload = function() {
        var xml = putXML(arr) ;
        document.getElementById('view').innerHTML = xml.replace(/[<>]/g, function($1){return $1 == '<' ? '&lt;' : '&gt;' ;}) ;
      }
    </script>
  </head>

  <body>
    <pre id="view"></pre>
  </body>
</html>

いまいちかも。

id:kreuz2nd

おお!これで思い通りの機能を搭載することが出来ました!

ありがとうございます。勉強させていただきます。

他にも解答例がありましたら、是非!

2009/08/16 13:58:48
id:GoldenDawn No.2

回答回数426ベストアンサー獲得回数81

ポイント23pt

気になる点をいくつか修正。

<html>
  <head>
    <script type="text/javascript">
      var arr = ["test/test1",
                 "名称未設定フォルダ 2/名称未設定フォルダ 1",
                 "名称未設定フォルダ 2/名称未設定フォルダ 4/名称未設定フォルダ 5"] ;

      function putXML(v) {
        var l = [] ;
        var r = '' ;

        for (var i = 0; i < v.length; ++i) {
          var b = v[i].split('/') ;
          for (var n = 0; n < b.length; ++n) {
            var e = 'l["' + b.slice(0, n+1).join('"]["') + '"]' ;
            eval('if (' + e + ' == undefined) ' + e + '=[];') ;
          }
        }

        function digg(i, d) {
          ++d ;
          var n = 0 ;
          for (var a in i) {
            if (n++ == 0 && d > 1) r += '>\n' ;
            r += Array(d).join('  ') + '<node label="' + a + '"';
            digg(i[a], d) ;
          }
          --d ;
          if (n == 0) r += ' />\n' ;
          else if (d > 0) r += Array(d).join('  ') + '</node>\n' ;
        }

        digg(l, 0) ;

        return r ;
      }

      onload = function() {
        var xml = putXML(arr) ;
        document.getElementById('view').innerHTML = xml.replace(/[<>]/g, function(m){return m == '<' ? '&lt;' : '&gt;' ;}) ;
      }
    </script>
  </head>

  <body>
    <pre id="view"></pre>
  </body>
</html>
id:kreuz2nd

すごい!短くなってる!

これなら勉強で解析しやすいかもと思って格闘してみたんですが、あまりに高度すぎて挫折してしまいました・・・。

これを機にレベルアップを図りたいと思います。ありがとうございました。

2009/08/16 17:23:34
id:GoldenDawn No.3

回答回数426ベストアンサー獲得回数81

ポイント22pt

せっかく回答上限があげられているので DOM を使った書き方で。

eval や再帰を使わない分、こちらの方が分かりやすいでしょうか。

<html>
  <head>
    <script type="text/javascript">
      var arr = ["test/test1",
                 "名称未設定フォルダ 2/名称未設定フォルダ 1",
                 "名称未設定フォルダ 2/名称未設定フォルダ 4/名称未設定フォルダ 5"] ;

      function putXML(v) {
        var t = document.createElement('root') ;
        var l = [] ;

        for (var i = 0; i < v.length; ++i) {
          var b = v[i].split('/') ;
          for (var n = 0; n < b.length; ++n) {
            var f = b.slice(0, n+1).join('/') ;
            if (l[f] == undefined) {
              l[f] = document.createElement('node') ;
              l[f].setAttribute('label', b[n]) ;
              if (n == 0) t.appendChild(l[f]) ;
              else l[b.slice(0, n).join('/')].appendChild(l[f]) ;
            }
          }
        }

        var xml = t.innerHTML ;
        xml = xml.replace(/(<node[^<]*)>\s*<\/node>/g, '$1 />') ;
        xml = xml.replace(/>/g, '>\n').split('\n') ;
        var r = '' ;
        for (var i = 0, d = 0; i < xml.length; ++i) {
          if (xml[i].match(/^<\//)) --d ;
          r += Array(d+1).join('  ') + xml[i] + '\n' ;
          if (xml[i].match(/\">$/)) ++d ;
        }

        return r ;
      }

      onload = function() {
        var xml = putXML(arr) ;
        document.getElementById('view').innerHTML = xml.replace(/[<>]/g, function(m){return m == '<' ? '&lt;' : '&gt;' ;}) ;
      }
    </script>
  </head>

  <body>
    <pre id="view"></pre>
  </body>
</html>

いずれにしても段階としては

  1. 与えられた配列を元に出力と同じ階層構造を構築
  2. 構築したデータを元に XML を出力

となります。

階層構造の構築には最初の回答では連想配列で、今回は DOM を使っています。今回も連想配列を使っていますが、階層構造ではなく、名前を並べているだけです。

出力に関しては連想配列の場合は各階層ごとにループを回して子ノードに対して再帰、と言う形です。

DOM の場合は終了タグも自動で付けてくれますが、空要素が求められている簡略表記ではないので変換しています。

どちらもインデントには Array(n+1).join(' ') を使っています。文字列の繰り返しに便利なやり方です。

id:kreuz2nd

いやー、重ね重ねありがとうございます。正確にはFLASH IDE用のJavaScriptですので、DOMは使えませんが、提示していただいた3つの回答を照らし合わせて読んでると、おかげさまで、なんとなくわかった気がします。

これはまだ僕のレベルには早すぎたみたいですが、じっくりやれば読み解けそうなので、ちょっと頑張ってみます。

それで、もしよければもうひとつ、確認だけでもいいのでお願いできるでしょうか。

タグの属性に「フォルダの階層」が必要になったので、これまた数時間かけて回答2に追記する感じで奮闘して見たのですが、ちょっと不安なので、見ていただければ嬉しいです。blockquoteの使い方が解らないので見辛いです。ご了承ください。

<node label="test" data="test">

  <node label="test1"data="test/test1" />

</node>

<node label="名称未設定フォルダ 2" data="名称未設定フォルダ 2">

  <node label="名称未設定フォルダ 1" data="名称未設定フォルダ 2/名称未設定フォルダ 1" />

  <node label="名称未設定フォルダ 4" data="名称未設定フォルダ 2/名称未設定フォルダ 4">

    <node label="名称未設定フォルダ 5" data="名称未設定フォルダ 2/名称未設定フォルダ 4/名称未設定フォルダ 5"/>

  </node>

</node>

という風にしたいので、試して悩んだりを繰り返した結果、最終的に

function putXML(v) {

var arr = v;

var l = [] ;

var r = '' ;

for (var i = 0; i < v.length; ++i) {

var b = v[i].split('/') ;

for (var n = 0; n < b.length; ++n) {

var e = 'l["' + b.slice(0, n+1).join('"]["') + '"]' ;

eval('if (' + e + ' == undefined) ' + e + '=[];') ;

}

}

var cnt = 0;

function digg(i, d) {

++d ;

var n = 0 ;

for (var a in i) {

if (n++ == 0 && d > 1) {

r += 'data="' + arr[cnt++] + '" >\n' ;

}

r += Array(d).join(' ') + '<node label="' + a + '"';</p>

digg(i[a].sort(sortFunc), d) ;

}

--d ;

if (n == 0) r += ' data="' + arr[cnt++] + '" />\n' ;

else if (d > 0) {

r += Array(d).join(' ') + '</node>\n' ;

}

}

digg(l, 0) ;

return r;

}

という感じになりました。かなり付け焼刃的ではありますが、一応機能はしてます。ただ付け焼刃過ぎて誤動作しそうなので、アドバイスを頂けると嬉しいです。

2009/08/16 22:30:10
id:GoldenDawn No.4

回答回数426ベストアンサー獲得回数81ここでベストアンサー

ポイント28pt

sortFunc の仕様が不明なので無視して動かしたら data 属性がおかしかったので sortFunc なしでの記述をば。

function putXML(v) {
  var l = [] ;
  var r = '' ;

  for (var i = 0; i < v.length; ++i) {
    var b = v[i].split('/') ;
    for (var n = 0; n < b.length; ++n) {
      var e = 'l["' + b.slice(0, n+1).join('"]["') + '"]' ;
      eval('if (' + e + ' == undefined) ' + e + '=[];') ;
    }
  }

  function digg(i, d, dt) {
    ++d ;
    var n = 0 ;
    for (var a in i) {
      if (n++ == 0 && d > 1) r += '>\n' ;
      r += Array(d).join('  ') + '<node label="' + a + '" data="' + dt + a + '"' ;
      digg(i[a], d, dt + a +'/') ;
    }
    --d ;
    if (n == 0) r += ' />\n' ;
    else if (d > 0) r += Array(d).join('  ') + '</node>\n' ;
  }

  digg(l, 0, '') ;

  return r ;
}
id:kreuz2nd

早っ!(笑

いやー・・・言葉が出ないというか、参りました。(汗

なるほど、パラメータを増やして、フォルダ名を再帰で渡すとは・・・まったく思いつきませんでした。よくよく考えれば、その考え方のほうが普通に出てくるはずなのに全く出てこなかったのが悔しいですねぇ。・・・この悔しさをバネに頑張ります。

sortFuncは消し忘れでした。(汗

本当に、本当にありがとうございました。凄く助かりました。また機会がありましたらよろしくお願いします!

2009/08/16 23:17:39

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません