하이브리드 앱 개발 중 InAppBrowser로 띄운 창에서 휴대폰 뒤로가기 물리버튼을 누를시 어플이 바로 종료되는것이 아니라 종료 여부를 한번 확인 후 종료해주고 싶어 방법을 한참 찾다가 해결해서 같은 문제로 방법을 찾아보셨다면 적용해보세요.

수정해야할 파일은  InAppBrowserDialog.java의 onBackPressed 입니다.

기본적으로 제공되는 파일내용은 아래와 같습니다.

 

public void onBackPressed () {
        if (this.inAppBrowser == null) {
            this.dismiss();
        } else {
            // better to go through the in inAppBrowser
            // because it does a clean up
            if (this.inAppBrowser.hardwareBack() && this.inAppBrowser.canGoBack()) {
                this.inAppBrowser.goBack();
            }  else {
                this.inAppBrowser.closeDialog();
            }
        }
    }

 

수정된 파일 내용은 아래와 같습니다.

브라우저가 history.back()이 가능한 상황이면 기존과 같이 뒤로가기를 지원해주고

종료되는 상황일시 그냥 종료하는것이 아니라 사용자에게 종료할지 confirm을 받고 종료를 원하면 종료를

취소를 원하면 기존창을 유지하는 것입니다.

 

파일의 경로는 {Projectname}\platforms\android\app\src\main\java\org\apache\cordova\inappbrowser\InAppBrowserDialog.java  입니다.

 

public void onBackPressed() {
        if (inAppBrowser == null) {
            dismiss();
        }
        else {
            // better to go through the in inAppBrowser
            // because it does a clean up
            if (inAppBrowser.hardwareBack() && inAppBrowser.canGoBack()) {
                inAppBrowser.goBack();
            }  else {
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context)
                        .setTitle("종료 확인")
                        .setMessage("종료하시겠습니까?")
                        .setPositiveButton("종료", new DialogInterface.OnClickListener(){
                            public void onClick(DialogInterface dialog, int which) {
                                inAppBrowser.closeDialog();
                            }
                        })
                        .setNegativeButton("취소", new DialogInterface.OnClickListener(){
                            public void onClick(DialogInterface dialog,int which){
                                dialog.cancel();
                            }
                        });
                alertDialogBuilder.create();
                alertDialogBuilder.show();
            }
        }
    }

 

 java 파일상단에 import도 추가해주세요

import android.content.DialogInterface;

 

 

적용된 화면은 이렇습니다.

종료 confirm

 

기존의 버전에서 버그가 있었는데요


$('#summernote').summernote('pasteHTML', '<p>aaa</p><p>bbb</p><p>ccc</p>');


이렇게 코딩을 작성하면 

예상하기론

aaa

bbb

ccc 

를 기대하게 되는데


실제로는 

ccc

bbb

aaa

이렇게 나오는 버그가 있었는데





0.8.11 버전의 pasteHtml 입니다

WrappedRange.prototype.pasteHTML = function (markup) {
var contentsContainer = $$1('<div></div>').html(markup)[0];
var childNodes = lists.from(contentsContainer.childNodes);

var rng = this.wrapBodyInlineWithPara().deleteContents();
if (rng.so >= 0) {
childNodes = childNodes.reverse();
}
childNodes = childNodes.map(function (childNode) {
return rng.insertNode(childNode);
});
if (rng.so > 0) {
childNodes = childNodes.reverse();
}
return childNodes;
};



0.8.12 버전의 pasteHtml 입니다

WrappedRange.prototype.pasteHTML = function (markup) {
var contentsContainer = $$1('<div></div>').html(markup)[0];
var childNodes = lists.from(contentsContainer.childNodes);
var rng = this.wrapBodyInlineWithPara().deleteContents();
if (rng.so > 0) {
childNodes = childNodes.reverse();
}
childNodes = childNodes.map(function (childNode) {
return rng.insertNode(childNode);
});
if (rng.so > 0) {
childNodes = childNodes.reverse();
}
return childNodes;
};


하늘색 음영부분이 수정되었는데요



if(rng.so >= 0) {  

이 부분이



if(rng.so > 0) {  

이렇게 바뀌었네요



해당부분을 위와 같이 수정해서 사용하고 있었는데



패치되어 새버전이 배포되었네요



과거버전 쓰시던 분이나 해당버그로 고생하시는 분들은 새로 받아 적용시켜보시면 이쁘게 나올겁니다


그리고 pasteHtml은 기존 에디터작업에 append를 해주는데 pasteHtml하는 내용으로 replace를 해주고싶다 하면


 $('#summernote').summernote('code', '');
$('#summernote').summernote('pasteHTML', '<p>aaa</p><p>bbb</p><p>ccc</p>');




이런식으로 추가해주면 초기화시킨후 새로 HTML을 넣어줄 수 있습니다


데이터 수집 혹은 연동을 할 때 중복된 데이터 없이 유일한 값만 갖고싶다면


아래를 봐주세요


우선 아래와 같이 샘플데이터를 만들어 줍니다




import pandas as pd

df = pd.DataFrame(columns=['id', 'desc'])

df.loc[0] = ["sbs", "aaa"]
df.loc[1] = ["kbs", "bbb"]
df.loc[2] = ["mbc", "ccc"]
df.loc[3] = ["ebs", "ddd"]
df.loc[4] = ["kbs", "eee"]




for index, row in df.iterrows():
print("id=%s, desc=%s" %(row.id, row.desc))



출력을 해볼까요?


id=sbs, desc=aaa

id=kbs, desc=bbb

id=mbc, desc=ccc

id=ebs, desc=ddd

id=kbs, desc=eee


id가 동일한게 'kbs'가 있군요 desc는 다르지만요


id로 중복제거를 해볼까요?


df2 = df.drop_duplicates('id', keep='first')

for index, row in df2.iterrows():
print("id=%s, desc=%s" % (row.id, row.desc))


drop_duplicates(중복제거할 기준컬럼, keep='first' or 'last')


keep은 first면 처음걸 두고 나머지를 제거할테고


last라면 반대로 마지막을 두고 그이전 중복데이터를 제거하겠죠


위의 출력결과를 보면


id=sbs, desc=aaa
id=kbs, desc=bbb
id=mbc, desc=ccc
id=ebs, desc=ddd

마지막 데이터인 kbs의 desc가 eee인 row가 제거되었네요 


잘됩니다


이번에는


df3 = df.drop_duplicates('id', keep='last')

for index, row in df3.iterrows():
print("id=%s, desc=%s" % (row.id, row.desc))

마지막을 남기도록 옵션을 주고 중복제거를 해봅니다


결과는 역시


id=sbs, desc=aaa
id=mbc, desc=ccc
id=ebs, desc=ddd
id=kbs, desc=eee

네 잘되네요


이번에는 컬럼을 하나 추가해서 샘플 데이터를 만들어 볼게요


df4 = pd.DataFrame(columns=['id', 'desc', 'num'])

df4.loc[0] = ["sbs", "aaa", "1"]
df4.loc[1] = ["kbs", "bbb", "1"]
df4.loc[2] = ["mbc", "ccc", "1"]
df4.loc[3] = ["ebs", "ddd", "3"]
df4.loc[4] = ["kbs", "eee", "2"]
df4.loc[5] = ["kbs", "bbb", "2"]

이렇게 num라는 컬럼을 하나 추가해주고


df5 = df4.drop_duplicates(['id', 'desc', 'num'], keep='last')

for index, row in df5.iterrows():
print("id=%s, desc=%s" % (row.id, row.desc))

중복제거를 해볼까요?


id=sbs, desc=aaa
id=kbs, desc=bbb
id=mbc, desc=ccc
id=ebs, desc=ddd
id=kbs, desc=eee
id=kbs, desc=bbb

중복이 없으니 중복제거가 안되네요


중복제거 기준에서 num을 빼준다면 "kbs"와 "bbb"가 중복되어 row를 제거할수 있겠네요


df5 = df4.drop_duplicates(['id', 'desc'], keep='last')
for index, row in df5.iterrows():
print("id=%s, desc=%s, num=%s" % (row.id, row.desc, row.num))

위와 같이 id와 desc를 중복 기준으로 주고 keep 라스트를 남긴다 자 결과는


id=sbs, desc=aaa, num=1
id=mbc, desc=ccc, num=1
id=ebs, desc=ddd, num=3
id=kbs, desc=eee, num=2
id=kbs, desc=bbb, num=2


중복제거 잘 되고 데이터도 마지막게 잘 남았네요


아래행 데이터가 아닌 전의 데이터를 유지하고 싶으면 어떻게 하면될까요?


keep 옵션만 first로 주면 되겠죠?


중복제거는 참 유용한거 같습니다


id기준 1000건 연동해야 한다면


중복제거 후 800건이 되면 200건은 연동하지 않아도 될테니까요


이상으로 pandas로 중복제거하는 방법이었습니다.

1편에서 pandas를 이용해 xml정보를 csv엑셀로 저장하는것을 해보았다.


그러다 특정 정보에서 charge라는 요금항목을 누락해서 xml return해주는 경우가 발생해서


오류가 났다.


☆ 정상 xml 리턴


<item>
<arrPlaceNm>전주</arrPlaceNm>
<arrPlandTime>201707011100</arrPlandTime>
<charge>20500</charge>
<depPlaceNm>상봉</depPlaceNm>
<depPlandTime>201707010800</depPlandTime>
<gradeNm>우등</gradeNm>
<routeId>NAEK040602</routeId>
</item>

누락된 xml 리턴

<item>
<arrPlaceNm>안동</arrPlaceNm>
<arrPlandTime>201707011000</arrPlandTime>
<depPlaceNm>서울경부</depPlaceNm>
<depPlandTime>201707010720</depPlandTime>
<gradeNm>우등</gradeNm>
<routeId>NAEK010840</routeId>
</item>



df.loc[i] = [item.arrplacenm.text, item.arrplandtime.text, item.charge.text, item.depplacenm.text,
AttributeError: 'NoneType' object has no attribute 'text'

Process finished with exit code 1


조건을 주어 에러를 방지해야하겠다.


기존의 코드는 이러했다.


for item in items.findAll("item"):

df.loc[i] = [item.arrplacenm.text, item.arrplandtime.text, item.charge.text, item.depplacenm.text,
item.depplandtime.text, item.gradenm.text, item.routeid.text]

i=i+1


에러방지를 위해 아래와 같이 추가해 주었다.


charge = "-"

for item in items.findAll("item"):

if (item.charge != None):
charge = item.charge.text
else:
charge = "-"

df.loc[i] = [item.arrplacenm.text, item.arrplandtime.text, charge, item.depplacenm.text,
item.depplandtime.text, item.gradenm.text, item.routeid.text]

i=i+1




item에 charge가 있을때만 가져오고 없을때는 -로 저장되도록 수정하고 정상적으로 작동되었다.


다른값들도 혹시나 하는 오류를 방지를 위해서 위와같이 변경해줘도 좋을것 같다.


# -*- coding: utf-8 -*-

import os
from bs4 import BeautifulSoup
from urllib.request import urlopen
import pandas as pd

output_path = "output"
output_file = "고속_test.csv"
if not os.path.exists(output_path):
os.makedirs(output_path)

df = pd.DataFrame(columns=['arrPlaceNm', 'arrPlandTime', 'charge', 'depPlaceNm', 'depPlandTime', 'gradeNm', 'routeId']) # 엑셀 헤더정보

i=0

url = 'xml정보 주소'

data = urlopen(url).read()
soup = BeautifulSoup(data, "html.parser")
items = soup.find("items")

for item in items.findAll("item"):

df.loc[i] = [item.arrplacenm.text, item.arrplandtime.text, item.charge.text, item.depplacenm.text,
item.depplandtime.text, item.gradenm.text, item.routeid.text]

i=i+1

df.to_csv(os.path.join(output_path, output_file), encoding='euc-kr', index=False)

위와 같이 pandas를 이용해 어렵지 않게 csv로 원하는 정보를 얻을수 있었다.


하지만 여기에서 문제가 발생했다.



위와같이 YYYYMMDDHHmm의 데이터를 지수형으로 표시해주고있다.

Ctrl + C로 복사후 메모장 같은 곳에 붙여 넣어도 지수형으로 붙여 넣어진다.


위 문제가 생긴 2개의 정보에 아래와 같이 코드를 추가해 주었다. 


df['arrPlandTime'] = '="' + df['arrPlandTime'] + '"'
df['depPlandTime'] = '="' + df['depPlandTime'] + '"'

 

이제 다시 엑셀을 확인해보자



엑셀에도 이쁘게 잘 나오고


복사 후 메모장 등에 붙여넣어도 정확하게 표시된다.



+ Recent posts