投稿者:坂本



はじめまして!
日本情報通信株式会社 バリューオペレーション本部EDIサービス部 社会人2年目の坂本です。
弊社のEDIサービス製品であるEDIPACKの開発を担当しております。

今回はXML形式でやり取りされる流通BMSの発注データを話題のGoogle Apps Script(以下:GAS)を使ってCSV変換してみました!


流通BMS利用者の変換事情
流通BMS(※)の通信では、JX手順や、ebXML、AS2等の通信プロトコルで、XML形式のデータのやり取りを行います。

しかし、中には「通信はXML形式でやり取りを行うが、自社のシステムではXML形式ではなく、
CSVや固定長のフォーマットでデータを扱っている。」という例も多々あります。

aeorwciuwerivuweirhk1.jpg

※流通BMS:流通業界日用品のEDI標準仕様 


GASで変換してみよう
そこで、今回はGoogleアカウントをお持ちであれば無料で使用できるGASを利用して
流通BMSのサンプルデータから、取引明細をCSV形式に変換してみます。

準備
・流通BMSのサンプルデータ「Order_sample_1_3.xml」
・新規作成したスプレッドシート

GAS作成
1.変換したい発注データを準備します。
今回は流通BMSのサンプルデータを利用します。(画像はXMLデータの取引明細の一部抜粋)

asrceoircmwe2.jpg

2.新規作成したスプレッドシートを準備し、シート2を作成しておきます。

erasraoirhewh3.jpg

3.ツール>スクリプトエディタからスクリプトエディタを開きます。

sarawoirqwhe3.jpg

4.エディタに下記コードを貼り付けます。
function xToc() {
// アクティブなスプレッドシート取得
let spsheet = SpreadsheetApp.getActive();
// シート名を指定しシート1を取得
let sheet1 = spsheet.getSheetByName("シート1");
// シート名を指定しシート2を取得
let sheet2 = spsheet.getSheetByName("シート2");
// その他変数設定
let scnt = sheet1.getLastRow(); // シート1の行数を取得
var a = 0; // nameタグ等が複数の意味として使われているためlineNumberタグ(取引明細番号(発注・返品))が来たら以降のタグを見るようにするためのカウント
var b = 1; // 行指定のためのカウント
var c = 1; // 列指定のためのカウント


// 処理開始
var values = {};
for(var i=1;i<=scnt;i++){
values[i] = sheet1.getRange(i, 1).getValue();
str=values[i];

// lineNumber(取引明細番号(発注・返品)の行に入ったら処理を始める)
if(trmTag1(str)=="lineNumber"){
a++;
}

if(a !=0){
if(trmTag1(str)=="lineNumber"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="gtin" && c <= 1){// 直前のタグが無かった場合の処理
c=2;
}
if(trmTag1(str)=="gtin"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag2(str)=="orderItemCode codeType" && c <= 2){// 直前のタグが無かった場合の処理
c=3;
}
if(trmTag2(str)=="orderItemCode codeType"){
sheet2.getRange(b,c).setValue(trmStr2(str));
c++;
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="supplierItemCode" && c <= 4){// 直前のタグが無かった場合の処理
c=5;
}
if(trmTag1(str)=="supplierItemCode"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="name" && c <= 5){// 直前のタグが無かった場合の処理
c=6;
}
if(trmTag1(str)=="name"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="name_sbcs" && c <= 7){// 直前のタグが無かった場合の処理
c=8;
}
if(trmTag1(str)=="name_sbcs"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="packingQuantity" && c <= 8){// 直前のタグが無かった場合の処理
c=9;
}
if(trmTag1(str)=="packingQuantity"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="fieldName" && c <= 9){// 直前のタグが無かった場合の処理
c=10;
}
if(trmTag1(str)=="fieldName"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag2(str)=="itemNetPrice unitPrice" && c <= 11){// 直前のタグが無かった場合の処理
c=12;
}
if(trmTag2(str)=="itemNetPrice unitPrice"){
sheet2.getRange(b,c).setValue(trmStr2(str));
c++;
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag2(str)=="itemSellingPrice unitPrice" && c <= 13){// 直前のタグが無かった場合の処理
c=14;
}
if(trmTag2(str)=="itemSellingPrice unitPrice"){
sheet2.getRange(b,c).setValue(trmStr2(str));
c++;
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="unitMultiple" && c <= 14){// 直前のタグが無かった場合の処理
c=15;
}
if(trmTag1(str)=="unitMultiple"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="unitOfMeasure" && c <= 15){// 直前のタグが無かった場合の処理
c=16;
}
if(trmTag1(str)=="unitOfMeasure"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="packageIndicator" && c <= 16){// 直前のタグが無かった場合の処理
c=17;
}
if(trmTag1(str)=="packageIndicator"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="quantity" && c <= 17){// 直前のタグが無かった場合の処理
c=18;
}
if(trmTag1(str)=="quantity"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="numOfOrderUnits" && c <= 18){// 直前のタグが無かった場合の処理
c=19;
}
if(trmTag1(str)=="numOfOrderUnits"){
sheet2.getRange(b,c).setValue(trmStr1(str));
c++;
}
if(trmTag1(str)=="\/lineItem"){
b++;
c=1;
}
}
}
}

// XMLタグをトリミングする
// <”tag”>name</tag>(一行)
function trmTag1(str){
str=str.slice(0,str.indexOf(">")).toString().replace("<","");
return str;
}
// 属性が入っているXMLタグをトリミングする
// <”tag key”=value>name</tag>
function trmTag2(str){
str=str.slice(0,str.indexOf("=")).toString().replace("<","");
return str;
}

// タグの値をトリミングする
// <tag>”name”</tag>
function trmStr1(str){
str=str.match(/>.*?</g).toString().replace("<","").replace(">","");
return str;
}

// 属性が入っているタグから値をトリミングする
// <tag key=”value”>name</tag>
function trmStr2(str){
str=str.match(/\".*?\"/g).toString().replaceAll("\"","");
return str;
}




5.スプレッドシートのシート1にXMLデータを貼り付けます。

asdkjhvlieurclehjg4.jpg

6.スクリプトを実行します。

asfdjkafgeiufo5.jpg

完了するとシート2に抽出した値が出力されます。

flkghodifgho6.jpg

7.ファイル>ダウンロード>カンマ区切りの値と選択し、csvデータとしてダウンロードします。

lskdakkwejhj7.jpg

8.ダウンロードしたファイルを任意のエディタで開くとCSVファイルに商品情報が抽出されていることを確認できます。

rwyeiurgweiru8.jpg



最後に
GASのプログラムを作成すると、流通BMSのサンプルデータのXML⇒CSV変換を行うことができます。

実際にこのプログラムのように業務要件に合わせて自社開発するとなるとマッピングや継承引継ぎによるコーディング、さらに、取引明細以外の情報も抽出したいといったデータの整形や変換等のカスタマイズの手間も多くかかります。

そこで、弊社では流通BMSの変換などに対応した「EDIPACK®/eXchange」という製品を提供しております。

sodifsdjfld9.jpg

EDIPACK®/eXchange」ではXMLデータ変換(XML・固定長・CSV)やデータの格納・継承機能、データの整形機能などをご利用いただくことが可能で、
流通BMSへ短期間で対応可能なXMLデータベースエンジンです。
詳しくはこちらをご覧ください。→https://www.niandc.co.jp/sol/product/edipack2/eXchange/

今回は流通BMSでのお困りごとについて書きましたが、弊社ではEDIに関する様々なお困りごとに対応した製品がございますので、興味をもっていただけましたらお気軽にご相談ください!