2019-06-23に更新

NodeJSでXMLをパースする

相変わらず、あちこち手を広げ過ぎてる気がしますが。

背景

カラオケ「DAM」のサーバから採点履歴のデータを取得する際、
RESTで返ってくるのがXMLなのでパース方法を調査した。

使うライブラリ

fast-xml-parser

パース対象とするデータ形式

<document xmlns="https://www.clubdam.com/app/damtomo/membership/MarkingDxListXML" type="2.2">
<result>
<status>OK</status>
<statusCode>0000</statusCode>
<message/>
</result>
<data>
<totalPage>40</totalPage>
<page>1</page>
<cdmCardNo>******</cdmCardNo>
</data>
<list count="5">
<data>
<marking requestNo="3809-63" artist="fripSide" contents="black bullet" play="0" reportCommentNo="2252" chartInterval="86" chartStability="75" chartExpressiveness="85" chartVibrateLongtone="85" chartRhythm="86" highPitch="79" lowPitch="56" highTessitura="67" lowTessitura="56" modulation="8" measure="15" sob="1" fall="2" timing="5" longTone="7" vibrato="5" vibratoType="1" vibratoSumSeconds="7.9" averageTotalPoint="80187" averagePitch="74" averageStability="67" averageExpressiveness="74" averageVibrateLongtone="53" averageRhythm="95" lastPoint="92804" date="2019/06/15 **:**:**">90.979</marking>
</data>
<data>
.....
</data>
</list>
</document>

パースオプション

attributeNamePrefix

パースした際にattributeのprefixにつける文字を指定する。

ignoreAttributes

これをtrueにしているとxmlのattributeを無視してしまう。
今回はmarkingの属性を取りたいのでfalse

var options = {

    attributeNamePrefix : "@_",
    attrNodeName: "attr", //default is 'false'
    textNodeName : "#text",
    ignoreAttributes : false,
    ignoreNameSpace : false,
    allowBooleanAttributes : false,
    parseNodeValue : true,
    parseAttributeValue : false,
    trimValues: true,
    cdataTagName: "__cdata", //default is 'false'
    cdataPositionChar: "\\c",
    localeRange: "", //To support non english character in tag/attribute values.
    parseTrueNumberOnly: false,
    attrValueProcessor: a => he.decode(a, {isAttributeValue: true}),//default is a=>a
    tagValueProcessor : a => he.decode(a) //default is a=>a
};

200件(上限)取ってくるコード

1ページに5件ずつあるのでカウンタjで40まで取りに行く。
resultArrayに結果を詰めていって、成功したらレスポンスとして返す。

    public loadData(req:express.Request,res:express.Response) :void{
        (async()=>{
            let cdmCardNo = '******'//ユーザ固有のtokenを入れる
            let url = 'https://www.clubdam.com/app/damtomo/membership/MarkingDxListXML.do?cdmCardNo='+ cdmCardNo
            let resultArray = []
            for(let j = 0 ; j < 40 ; j++){
                let response = await fetch(url + '&pageNo=' + (j + 1))
                let data = await response.text()
                //let data = response.json()
                let xmlData = parser.parse(data ,options);
                console.log(xmlData)
                if(xmlData.document.list.data === undefined){
                    break;
                }
                for(let i = 0; i < xmlData.document.list.data.length; i++){
                    resultArray.push(xmlData.document.list.data[i])
                }
            }
            res.json(resultArray)
        })().catch(err=>{
            console.error(err)
            res.sendStatus(500)
        })
    }


ckoshien

個人開発4年目。普段はアプリケーションエンジニア。 ReactJS/NodeJS/ReactNative/Java

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント