use-file-uploadを使ってXMLファイルをアップロードしてパースする手順のメモです
use-file-upload
今回はuse-file-uploadを使用しました
https://www.npmjs.com/package/use-file-upload
use-file-uploadはReactフックとして動作するライブラリで、useFileUpload()でstateを作っておいて、buttonなどからonclickで呼ぶ事でアップロードしたファイルをstateとして扱えるようにしてくれます。
以下の例のsource, name, size, fileはそれぞれblob url, ファイル名、ファイルサイズ、ファイルオブジェクトになります。画像ファイルをアップロードして表示する場合は、blob urlであるsourceをimgタグのsrcに与える事でサーバー上のファイルと同様に表示できます。
import React from 'react'
import { useFileUpload } from 'use-file-upload'
const App = () => {
const [file, selectFile] = useFileUpload()
return (
<div>
<button
onClick={() => {
// Single File Upload
selectFile({}, ({ source, name, size, file }) => {
// file - is the raw File Object
console.log({ source, name, size, file })
// Todo: Upload to cloud.
})
}}
>
Click to Upload
</button>
{file ? (
<div>
<img src={file.source} alt='preview' />
<span> Name: {file.name} </span>
<span> Size: {file.size} </span>
</div>
) : (
<span>No file selected</span>
)}
</div>
)
}
export default App;
上記の例ではbuttonタグにCSSを設定せずに表示するので以下のようなシンプルなボタンが表示されます
アップロードしたXMLファイルをオブジェクトに変換
fileオブジェクトを直接触るやり方が分からなかったので、blob urlをXMLHttpRequestで読んでくるやり方でやりました。XMLHttpRequestでblobを読みに行ってresponseXMLでXMLとして取得します。XMLとして読めなかった場合はresponseXMLにnullが入りますので、nullでなかった場合は表示するというようにしました。
import React from 'react'
import { useFileUpload } from 'use-file-upload'
function applyGPX(xml){
console.log(xml);
};
function getXML(source) {
console.log('source:');
console.log(source);
var xhr = new XMLHttpRequest();
xhr.onload = function(e){
const xml = xhr.responseXML;
if (xml != null){
applyGPX(xml);
} else {
console.log('not xml file');
}
};
xhr.open("GET", source);
xhr.send();
};
const App = () => {
const [file, selectFile] = useFileUpload()
return (
<div>
<button
onClick={() => {
selectFile({}, ({ source, name, size, file }) => {
getXML(source);
})
}}
>
Click to Upload
</button>
{file ? (
<div>
<span> Name: {file.name} </span>
<span> Size: {file.size} </span>
</div>
) : (
<span>No file selected</span>
)}
</div>
)
};
export default App;
xmlオブジェクトからほしい情報を拾う
XMLオブジェクトが作れたのでほしい情報を拾っていこうと思います。XMLHttpRequest.responseXMLで取得したオブジェクトはgetElementsByTagName(), getElementById(), getElementsByClassName()などで取得できます。
const elements = hoge.getElementsByTagName('fuga')
const elements = hoge.getElementById('fuga')
const elements = hoge.getElementsByClassName('fuga')
また、取得したelementのattributeは以下のように取得できます
const attribute = elements[0].getAttribute('foo')
今回はgpxファイルを読み込むので以下のようにして緯度、経度、高度を取得しました。
function getTracks(xml){
console.log('getTracks');
const trackTags = xml.getElementsByTagName('trkpt');
console.log('track length: ' + trackTags.length);
var tracks = [];
var elevations = [];
for(let k = 0; k < trackTags.length; k++) {
let element = trackTags[k];
let latitude = parseFloat(element.getAttribute('lat'));
let longitude = parseFloat(element.getAttribute('lon'));
tracks.push([latitude, longitude]);
let element2 = element.getElementsByTagName('ele')[0]
let elevation = parseFloat(element2.innerHTML)
elevations.push(elevation);
};
console.log([tracks, elevations]);
return [tracks, elevations]
余談
use-file-upload以外にもいくつかReact用のアップロードライブラリを試したんですが、blobぐらい分かるよね?的なノリで書いてあって地味に苦戦しました。ウェブ関係のライブラリ制作者が常識だから省いても良いと思っている部分を勉強できる本があったら読みたいので、ご存知の方がいらっしゃいましたら教えて下さい。