요즘 부동산 플랫폼을 만들어보고 싶어서 api 사용하는 연습도 할겸

공공데이터 api키를 발급받고 데이터를 뿌려보려고 했었는데 

우연히 그런건지 받는 api가 xml 데이터였다

 

하지만 난 Json과 map()을 사랑하는 사람이라

json변환 방법을 찾았는데

 

언제나 그렇듯 흔하게 나오는 json.parse()로는 문법 오류가 났다

(데이터 구조가 이미 json형식일 경우 아님)

 

찾아보니 라이브러리 혹은 직접 해야하는데 검색하다 라이브러리를 사용하지 않고 쉽게 변환할 수 있는

좋은 코드를 받게 되서 공유한다.

function xmlToJson(xml) {
    // Create the return object
    var obj = {};

    if (xml.nodeType == 1) {
        // element
        // do attributes
        if (xml.attributes.length > 0) {
        obj["@attributes"] = {};
        for (var j = 0; j < xml.attributes.length; j++) {
            var attribute = xml.attributes.item(j);
            obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
        }
        }
    } else if (xml.nodeType == 3) {
        // text
        obj = xml.nodeValue;
    }

    // do children
    // If all text nodes inside, get concatenated text from them.
    var textNodes = [].slice.call(xml.childNodes).filter(function(node) {
        return node.nodeType === 3;
    });
    if (xml.hasChildNodes() && xml.childNodes.length === textNodes.length) {
        obj = [].slice.call(xml.childNodes).reduce(function(text, node) {
        return text + node.nodeValue;
        }, "");
    } else if (xml.hasChildNodes()) {
        for (var i = 0; i < xml.childNodes.length; i++) {
        var item = xml.childNodes.item(i);
        var nodeName = item.nodeName;
        if (typeof obj[nodeName] == "undefined") {
            obj[nodeName] = xmlToJson(item);
        } else {
            if (typeof obj[nodeName].push == "undefined") {
            var old = obj[nodeName];
            obj[nodeName] = [];
            obj[nodeName].push(old);
            }
            obj[nodeName].push(xmlToJson(item));
        }
        }
    }
    return obj;
}

https://velog.io/@duboo/javascript-XML-to-JSON-%EB%B3%80%ED%99%98 출처

 

var lo = '구로구';
var xhr = new XMLHttpRequest();
var xmlDoc;
let xmlParser = new DOMParser();
let list = document.getElementById('list');
xhr.open('GET', url);
// xhr.responseType = 'json'
xhr.onreadystatechange = function () {
    if (this.readyState == xhr.DONE) {  // <== 정상적으로 준비되었을때
        if(xhr.status == 200||xhr.status == 201){ // <== 호출 상태가 정상적일때
            xmlDoc = xmlParser.parseFromString(xhr.response, "text/xml");
            var result = xmlToJson(xmlDoc);
            result.tbLnOpendataRtmsV.row.map(h => {
                if(h.HOUSE_TYPE == "아파트"){
                    console.log(h);
                    $(list).append(`
                    <details>
                        <summary>${h.BLDG_NM}</summary>
                        <ul>
                            <li class="h_attr">거래일자 : ${h.DEAL_YMD}</li>
                            <li class="h_attr">소속지역 : ${h.SGG_NM}</li>
                            <li class="h_attr">소속 동 : ${h.BJDONG_NM}</li>
                            <li class="h_attr">주거형태 : ${h.HOUSE_TYPE}</li>
                            <li class="h_attr">실거래금액 : ${h.OBJ_AMT}</li>
                        </ul>
                    </details>`
                    );
                }
            });
        }
    }
};

현재 테스트용으로 쓰고 있는 코드 (발급받은키) 자리에 서울 공공데이터 api키를 발급받아서 넣으면..!

 

깔끔하게 변환되었다.

 

지난 시간에 이어서 반대로 부모창에서 iframe 컨텐츠에 접근 하는 방법을 알아보자

 

오늘도 작성하기 전에 확인하면서 나도 다시 검색해봤는데 시키는대로 해도 안잡히거나 제어가 안되는 경우가 많다

당연하다고 생각해서 안 알려주는건지 모르겠지만 나처럼 1 to 10 봐야하는 분들을 위해 안되는 경우도 공유한다.

 

보통 검색했을때 제일 많이 나오는 부분

  var contents = document.getElementById("vr-frame").contentWindow.document.getElementById("iframe_content");
  var j_contents = $('iframe').contents().find('#iframe_content');

바닐라로 contentWindow를 사용하거나

제이쿼리로 .contents().find면 뚝딱인가 싶더니

 

시키는대로 했는데..

 

아무고토 안나온다

이유는 아이프레임이 로드되기전에 찾아서 그렇다

지난번에도 일할때 잠깐 화났던 기억이..

간단하게 iframe이 로드되고 스크립트를 실행시켜주면 문제가 없다

해결

document.querySelector('iframe').addEventListener("load", function() {
  var contents = document.getElementById("vr-frame").contentWindow.document.getElementById("iframe_content");
  var j_contents = $('iframe').contents().find('#iframe_content');
  j_contents.addClass('controls');
  console.log(contents, j_contents);
});

지금 다니는 회사에서는 팝업이든 새창이든 컨텐츠를 iframe으로 보여주는 경우가 많다

보통 부모창에서 iframe 안에 요소를 가져오거나 반대의 경우가 최근 자주 보게 되어 기록하게 되었다.

오늘은 iframe 내부에서 부모가 사용하는 변수 가져오기! (반대 경우보다 좀 쉽다)

 

간단한 html 예

간단하게 같은 경로에 위치한 곳에 있는 파일이라고 가정하고 openLabel 이라는 변수를 생성해두었다

 

iframe내부에서는 아래 코드만 작성하면 된다

window.top.가져올변수이름

  <script>
    var label = window.top.openLabel;
    console.log(label);
  </script>

쉽다.

다음엔 반대의 경우 부모창에서 iframe의 내부에 진입해보자!

이번에 회사에서 업무 중에 외부에서 가져온 소스에 innerHTML로 덕지덕지 만들어 놓은 코드를 보게 되었다..

그런 태그들에 이벤트를 주려고 했는데 나만 그런건지 모르겠는데 검색해도 잘 안나오고 찾기 힘들어서 테스트로 공유하려고 한다

innerHTML로 추가할 태그의 css를 미리 넣어놓은 html
로드되면 testP라는 클래스를 가진 p태그 추가
css까지 잘 반영된 화면

분명 css는 로드된 이후에 잘 들어가는걸 확인할 수 있는데.. 

여기서 밖에서 testP태그의 클래스 이름으로 이벤트를 넣으려고 하면 이벤트가 바인딩되지 않는다.

웃긴건 이후에 console에 찍으면 찍힘

뒤적거려본 결과 돔 생성되고 하는 순서로 인해 안된다는거 같은데

결론만 말하자면 미리 innerHTML 안에 인라인으로 이벤트를 넣어줘야 한다

 

요로코롬
잘 나온다!

 

이게 뭐라고 30분정도 머리썼는데 약간 현타왔다 처음부터 이 방법으로 했다면 당신은 천재... 

학은제 과제로 성적 계산기 만들기가 나왔다.. 겸사겸사 공유한다.

과제 조건

우선 3명의 이름과 성적을 입력받고 제출 버튼을 클릭하면 순위대로 이름, 총점, 평균을 출력하는 코드를 작성했다.

<body>
  <h2>성적 계산기</h2>
  <form action="post" name="grade">
    <p>이름 : <input type="text" size="4" name="name1"> 국어 : <input type="text" size="4" name="kor1"> 영어 : <input type="text" size="4" name="eng1"> 수학 : <input type="text" size="4" name="math1"></p>
    <p>이름 : <input type="text" size="4" name="name2"> 국어 : <input type="text" size="4" name="kor2"> 영어 : <input type="text" size="4" name="eng2"> 수학 : <input type="text" size="4" name="math2"></p>
    <p>이름 : <input type="text" size="4" name="name3"> 국어 : <input type="text" size="4" name="kor3"> 영어 : <input type="text" size="4" name="eng3"> 수학 : <input type="text" size="4" name="math3"></p>
    <input type="button" value="제출" onclick="result()">
    <p>이름 : <input type="text" size="4" name="1th"> 총점 : <input type="text" size="4" name="sum1"> 평균 : <input type="text" size="4" name="avg1"> 순위 : <input type="text" size="4" name="rank1"></p>
    <p>이름 : <input type="text" size="4" name="2th"> 총점 : <input type="text" size="4" name="sum2"> 평균 : <input type="text" size="4" name="avg2"> 순위 : <input type="text" size="4" name="rank2"></p>
    <p>이름 : <input type="text" size="4" name="3rd"> 총점 : <input type="text" size="4" name="sum3"> 평균 : <input type="text" size="4" name="avg3"> 순위 : <input type="text" size="4" name="rank3"></p>
  </form>
</body>

simple is best

제출 버튼을 눌렀을 때 main.js에서 만든 result() 함수가 실행되고 최소한 이름이나 성적에 빈칸이 있을 경우 제출하지 못하게 경고 창을 띄워주고 (정확하겐 이름엔 텍스트만 입력되고 성적엔 숫자만 입력되게 해주는 좋다)

 

function result() {
  if(grade.kor1.value === "" || grade.kor2.value === "" || grade.kor3.value === "") {
    alert('국어 점수를 입력해주세요');
  } else if (grade.name1.value === "" || grade.name2.value === "" || grade.name3.value === ""){
    alert('학생의 이름을 입력해주세요');
  } else if (grade.eng1.value === "" || grade.eng2.value === "" || grade.eng3.value === ""){
    alert('영어 점수를 입력해주세요');
  } else if (grade.name1.value === "" || grade.name2.value === "" || grade.name3.value === ""){
    alert('수학 점수를 입력해주세요');
  }
}

빈칸이 없이 잘 입력되었을 경우 계산이 시작된다.

 

여기서 값을 입력 받고 평균과 등수를 정해서 출력해줘야 하는데.. 하나씩 비교해가면서 쓰는건 좀 아닌거 같아서 찾아보니 아주 좋은 코드가 있었다.

 

    var sum1 = parseInt(grade.kor1.value) + parseInt(grade.eng1.value) + parseInt(grade.math1.value);
    var sum2 = parseInt(grade.kor2.value) + parseInt(grade.eng2.value) + parseInt(grade.math2.value);
    var sum3 = parseInt(grade.kor3.value) + parseInt(grade.eng3.value) + parseInt(grade.math3.value);

    const sumArray = [sum1, sum2, sum3];
    const answer = [];
    const ranking = [...sumArray].sort((a,b)=>b-a);
    for(let n of sumArray) {
      answer.push(ranking.indexOf(n)+1)
    }

우선 입력받은 값들을 저장하고 배열에 넣은 다음 등수를 저장할 빈 배열을 만들고 랭킹에서 오름차순 정렬으로 점수 배열의 값들을 돌려서 빈 배열에 인덱스 +1로 넣어준다. 그러면 동점 처리까지 완벽..

 

main.js 전체 코드

function result() {
  if(grade.kor1.value === "" || grade.kor2.value === "" || grade.kor3.value === "") {
    alert('국어 점수를 입력해주세요');
  } else if (grade.name1.value === "" || grade.name2.value === "" || grade.name3.value === ""){
    alert('학생의 이름을 입력해주세요');
  } else if (grade.eng1.value === "" || grade.eng2.value === "" || grade.eng3.value === ""){
    alert('영어 점수를 입력해주세요');
  } else if (grade.math1.value === "" || grade.math2.value === "" || grade.math3.value === ""){
    alert('수학 점수를 입력해주세요');
  } else {
    var sum1 = parseInt(grade.kor1.value) + parseInt(grade.eng1.value) + parseInt(grade.math1.value);
    var sum2 = parseInt(grade.kor2.value) + parseInt(grade.eng2.value) + parseInt(grade.math2.value);
    var sum3 = parseInt(grade.kor3.value) + parseInt(grade.eng3.value) + parseInt(grade.math3.value);

    const sumArray = [sum1, sum2, sum3];
    const answer = [];
    const ranking = [...sumArray].sort((a,b)=>b-a);
    for(let n of sumArray) {
      answer.push(ranking.indexOf(n)+1)
    }
   
    grade.rank1.value = answer[0];
    grade.rank2.value = answer[1];
    grade.rank3.value = answer[2];

    var avg1 = sum1 / 3;
    var avg2 = sum2 / 3;
    var avg3 = sum3 / 3;

    grade.first.value = grade.name1.value;
    grade.sec.value = grade.name2.value;
    grade.thr.value = grade.name3.value;

    grade.sum1.value = sum1;
    grade.sum2.value = sum2;
    grade.sum3.value = sum3;

    grade.avg1.value = avg1;
    grade.avg2.value = avg2;
    grade.avg3.value = avg3;
   
  }
}

짜잔 참 쉽죠?

+ Recent posts