Node.jsモジュールxml2jsを使用しようとしています
私のコードは非常に簡単です:
function testparse(pathname, callback) {
var parser = require('xml2js').Parser(),
util = require('util'),
fs = require('fs'),
fs.readFile(pathname, function (err, data) {
parser.parseString(data, function(err, result) {
console.log('Complete result:');
console.log(util.inspect(result, {depth: null})); //Work
console.log('Try to access element:');
console.log(result.smil.body); //Work
console.log(result.smil.body.update); //Undefined
});
});
}
私のxmlファイルは次のとおりです:
<?xml version="1.0"?>
<smil>
<head/>
<body>
<update /*some field*//>
<stream name="name"/>
<playlist /*some field*/>
<video /*some field*//>
<video /*some field*//>
<video /*some field*//>
</playlist>
</body>
</smil>
出力は私に与えます:
Complete result:
{ smil:
{ head: [''],
body:
[ { update: [[Object]],
stream: [[Object]],
playlist: [[Object]] } ] } }
Try to access element:
[Object]
Undefined
私は試して身体にアクセスすることに成功しましたが、今私は立ち往生しています。
疑問に思っている人のために、xml2jsは配列の使用と乱用
私のファイルの場合、ツリーは次のようになります。
.result //Object
|_.head //Array
|_.body //Array
|_.update //Array
| |_.$ //Object
| |_.fields //Strings
|
|_.stream //Array
| |_.$ //Object
| |_.fields //Strings
|
|_.playlist //Array
|_.$ //Object
|_.fields //Strings
|
|_.video //Array
|_.$ //Object
|_.fields //Strings
xml2js にはうらやましいタスクがあります。スキーマを事前に知らなくても、逆にできる方法でXMLをJSONに変換します。最初は明らかです。
<name>Fred</name> → { name: "Fred" }
<chacha /> → { chacha: null }
これまでのところ簡単ですか?これはどうですか?
<x><y>z</y><x>
人間にわかりやすい名前を削除すると、xml2js
。最初は、これは非常に合理的だと思うかもしれません:
{ x: { y: "z" } }
後で、このXMLテキストを調べて、推測されたスキーマが間違っていることに気付きます。
<x><y>z</y><y>z2</y></x>
ええとああ。たぶん、配列を使うべきだった。少なくともすべてのメンバーに同じタグがあります:
{ x: [ "z", "z2" ] }
しかし、必然的に、それは近視眼的であることがわかります。
<x><y>z</y><y>z2</y><m>n</m>happy</x>
あの...
{ x: [ { y: "z" }, { y : "z2" }, { m: "n" }, "happy" ] }
...そして、誰かがいくつかの属性とXML名前空間であなたを磨き上げます。
より簡潔な出力スキーマを構築する方法は明らかです。タグおよび属性名から詳細を推測できます。あなたはそれを理解しています。
ライブラリはその理解を共有しません。
ライブラリがスキーマを認識しない場合、配列、オブジェクトの追加レイヤー、特別な属性名、または3つすべてを「使用および悪用」する必要があります。
唯一の選択肢は、可変出力スキーマを使用することです。上記で見たように、それは最初は単純に保ちますが、すぐに大量の条件付きコードを書くことに気付くでしょう。同じタグ名を持つ子がリストに折りたたまれた場合、どうなるかを考えてみましょう。ただし、複数ある場合のみです。
if (Array.isArray(x.y)) {
processTheYChildren(x.y);
} else if (typeof(x.y) === 'object') {
// only one child; construct an array on the fly because my converter didn't
processTheYChildren([x.y]);
} else ...
TL; DR:見た目よりも難しい。他のJSON側の表現の詳細については、Open311 JSONおよびXML変換 ページをお読みください。すべての「使用および悪用」配列、オブジェクトの追加レイヤー、元のXMLに表示されなかった名前を持つメンバー、または3つすべて。
xml2jsのドキュメントの状態 のように、プロパティexplicitArray
をfalse
に設定することで、配列を乱用しないようにパーサーを設定できます(重要:ブール値である必要があります)ストリングとしての値"false"
はただnot動作します!)
例:
var parser = new xml2js.Parser({explicitArray : false});
これにより、JSONプロパティにはるかに簡単にアクセスできるようになります。これが誰にも役立つことを願っています。
返されるJSONはJavaScriptに対応しすぎていません。作業しやすくするヘルパー関数を作成しました。
使用する前に必ず読んで、その機能を理解してください。
xml.parseString(xmlString, function(err, results){
if(err) throw err
results = cleanXML(results);
});
var cleanXML = function(xml){
var keys = Object.keys(xml),
o = 0, k = keys.length,
node, value, singulars,
l = -1, i = -1, s = -1, e = -1,
isInt = /^-?\s*\d+$/,
isDig = /^(-?\s*\d*\.?\d*)$/,
radix = 10;
for(; o < k; ++o){
node = keys[o];
if(xml[node] instanceof Array && xml[node].length === 1){
xml[node] = xml[node][0];
}
if(xml[node] instanceof Object){
value = Object.keys(xml[node]);
if(value.length === 1){
l = node.length;
singulars = [
node.substring(0, l - 1),
node.substring(0, l - 3) + 'y'
];
i = singulars.indexOf(value[0]);
if(i !== -1){
xml[node] = xml[node][singulars[i]];
}
}
}
if(typeof(xml[node]) === 'object'){
xml[node] = cleanXML(xml[node]);
}
if(typeof(xml[node]) === 'string'){
value = xml[node].trim();
if(value.match(isDig)){
if(value.match(isInt)){
if(Math.abs(parseInt(value, radix)) <= Number.MAX_SAFE_INTEGER){
xml[node] = parseInt(value, radix);
}
}else{
l = value.length;
if(l <= 15){
xml[node] = parseFloat(value);
}else{
for(i = 0, s = -1, e = -1; i < l && e - s <= 15; ++i){
if(value.charAt(i) > 0){
if(s === -1){
s = i;
}else{
e = i;
}
}
}
if(e - s <= 15){
xml[node] = parseFloat(value);
}
}
}
}
}
}
return xml;
};
例:
{
queries: { query: [ {}, {}, {} ] }
}
になる
{
queries: [ {}, {}, {} ]
}
そして
{
types: { type: [ {}, {}, {} ] }
}
になる
{
types: [ {}, {}, {} ]
}
また、安全に整数/浮動小数点を変換します。
編集:for ... inをforに置き換え
結果全体を表示するconsole.log(util.inspect(result, false, null))
を試してください。
私にとっては、console.dirの問題であり、より正確には非問題でした。
出力をconsole.dirしたときに同じ結果が得られました。
{
TextView: [ [Object] ],
ImageView: [ [Object] ] } }
しかし、console.dirの制限であり、データが実際にそこにあることを知って驚いた。どうやらconsole.dirはいくつかのレベル以上を表示しません。 console.dirをより深いレベルにすると、データがそこにありました:
console.log(result.RelativeLayout.TextView);
出力:
{ '$':
{ 'Android:layout_width': 'wrap_content',
'Android:layout_height': 'wrap_content',
'Android:layout_marginLeft': '10dp',
'Android:layout_marginTop': '10dp',
'Android:textColor': '#ffffff',
'Android:id': '@+id/textView',
'Android:text': 'Hello World!' } }
私は他のライブラリを探し始めました。それが誰かを助けてくれるなら。