짜투리

[xml/DB 프젝-데이터 통합] 엑셀로 xml문서 만들기+자바 DOM Parser+XML valid+XML 파일 XSD 만들기

소곡이 2021. 12. 7. 21:13
728x90

 3시간 걸려서 글 다 썼는데 왠지 모르게 다 날라가서 다시 쓴다... 

 

 오늘은 이번 학기 나의 노화의 주범.. xml/db 프로젝트의 데이터 통합 과정을 적으려고 한다. 솔직히 많은 사람의 도움을 받아서 온전히 내가 했다고 할 수 있는 것이 없어 굉장히 부끄럽다. 

 

 나의 프로젝트를 도와준 모든 분들에게 이 글을 바친다. 


<엑셀로 csv 파일을 xml 문서로 만들기>

도움을 주신 분 : 싸가지 오빠

 

1. csv 파일 불러오기 + xml 문서 작성

  데이터는 총 72,632개.

 

 저 데이터를 xml로 만들기 위해서는 xml 문서가 필요하다. csv 파일을 xml로 만들건데 그러기 위해서는 xml문서가 필요한다는게 대게 모순적이라 생각했는데. 

 

 

 그냥 요렇게 원하는 xml 형식을 대충 정한다. 이때 중요한건 단위가 되는 태그(우리의 경우 sentence)를 하나만 하면 안 되니까 복붙해서 두개 정도 만든다. 

 

2. 개발자 도구 설정

: 옵션> 리본 사용자 지정> 개발 도구> 원본> xml 맵 > 추가(1에서 만든 xml문서 추가)> 루트 태그를 drag

 

 여기서 무슨 알림 문자 뜨는데 그냥 무시한다. 

 

 

 최상위 노드를 엑셀 처음에 드래그하고 놓으면 아래와 같이 된다. 

 

 

3. xml 형식으로 저장

 다른 이름으로 저장할 때 형식을 xml로 해준다.

 

주의

 저장된 xml 파일을 열고 자세히 보면 네임스페이스가 이상한데, 그건 vscode->ctrl+F를 통해서 간단하게 수정할 수 있다. 


<자바 돔 파서>

 사실 처음 계획을 데이터 통합을 엑셀로 하려고 했다. DB를 csv파일로 변환하여 엑셀에서 csv파일을 xml파일로 만드는 것이다. 그러나 DB에는 하나의 스키마에 필요한 데이터들이 여러 테이블에 나뉘어져 있다. 이 테이블들을 csv파일로 만들려면 한 테이블을 만들어야 하는데 우리 데이터 특성상 null값이 많이 들어가게 된다..

 

 그래서 돔파서를 쓰게 된 것! (그니까 위에 엑셀->xml은 할 필요도 없었던 것...)

 

1. DB 연결 + JDBC

 사실 DB는 팀원인 핑퐁 오빠가 만들어서 내 DB에는 없다. 그래서 오빠의 DB에 연결했고 연결은 아래 사이트를 참고했다.

 

https://we-always-fight-with-code.tistory.com/6

 

[ MySQL ] 데이터베이스 공유 & 타 데이터베이스 접속하기

[MySQL 데이터베이스를 로컬에서까지는 다룰 수 있는 사람 대상의 자료입니다. 필자역시 초보이니 100%신뢰는 X.] MySQL은 하나의 데이터베이스(서버)를 여러 사람 또는 PC가 공유할 수 있다. 근데 그

we-always-fight-with-code.tistory.com

 

 JDBC 코드는 핑퐁 오빠한테 협찬 받았다.

package lecture16;
import java.sql.*;

public class databaseProject3  {

   public static void main(String[] args) {
      Connection conn;
      Statement stmt = null;
      try {
         Class.forName("com.mysql.jdbc.Driver");
         conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/스키마 이름", "root 이름", "루트 비번");
         System.out.println("DB 연결 완료");
         stmt = conn.createStatement();
         
         stmt.executeUpdate("use verbal_violence;");
         System.out.println("테이블 변경");
         
         ResultSet srs = stmt.executeQuery("select * from speakers;");
         while(srs.next()) {
            int id = srs.getInt("speakers_id");
            String g = srs.getString("gender");
            String a = srs.getString("age");
            System.out.println(id+", "+g+", "+a);
         }
         
      } catch (ClassNotFoundException e) {
         System.out.println("JDBC 드라이버 로드 에러");
      } catch (SQLException e) {
         System.out.println("SQL 실행 에러");
      }
   }
}

 

2. 돔파서 코드

 아래 그림과 같은 구조의 xml 파일을 만들거다. 참고 사이트는 아래와 같다.

https://huskdoll.tistory.com/869

 

java로 xml 생성

java 로 xml 생성 하는 소스 입니다. 인터넷으로 검색한 결과 가장 이해하기 쉽고 간단한 소스 같습니다. 저같은 경우 정렬문제와 standalone="no" 이 상위에 포함되는 문제가 있었는데 해당 소스에서

huskdoll.tistory.com

	    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
	    DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            // doc 생성
            Document doc = docBuilder.newDocument();
            doc.setXmlStandalone(true); //standalone="no" 를 없애준다.
            System.out.println("XML 변환 시작");

            //root노드
            Element data = doc.createElement("words");
            doc.appendChild(data);

            //======여기부터 추가===========

            int id=0;
            for(int i=0; i<word_vec.size(); i++) {
                Element word = doc.createElement("nif:word");    //자식노드에 태그(요소)추가하기
                id += 1;
                word.setAttribute("word_id", String.valueOf(id));  //★★★★★★속성값 추가
                data.appendChild(word);

                //요소
                Element w = doc.createElement("element");              //요소 추가
                w.appendChild(doc.createTextNode(word_vec.get(i)));    //요소의 값 추가
                word.appendChild(w);                                   //word의 하위 태그

                //형태소
                Element mor = doc.createElement("gold:morpheme");   
                mor.appendChild(doc.createTextNode(mor_vec.get(i)));       
                word.appendChild(mor);

                //슬랭랭
                Element slang = doc.createElement("wikipedia:slang");    
                slang.appendChild(doc.createTextNode(String.valueOf(slang_vec.get(i))));        
                word.appendChild(slang);
            }

 

 여기서 요소의 값을 추가할 때 벡터에서 값을 가져오는 걸 알 수 있다. 이렇게 하면 굉장히 비효율적인게 DB 테이블이 여러개다 보니 필요한 vector가 무려 10개가 나온다. 

 

 

 데이터가 7만개가 넘는데 당연히 말도 안 되게 비효율적인 코드라는 뜻.

 

 

 지금까지는 빌드업이었다.

 내가 제출 전날까지 데이터 통합 코드를 못 짰다... 정말 죽일놈이지. 그래서 핑퐁 오빠가 코드 좀 달라고 하고 2시간 쯤 흘렀을까. 오빠가 내가 이틀 밤을 새워도 못 했던 통합 코드를 짰다. 

 

public static void main(String[] args) {
        Connection conn;
        Statement stmt = null;
        try {
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();

            // doc 생성
            Document doc = docBuilder.newDocument();
            doc.setXmlStandalone(true);

            System.out.println("XML 변환 시작");

            //root노드
            Element classification = doc.createElement("classification");
            doc.appendChild(classification);

            Element data = doc.createElement("wekipedia:data");
            classification.appendChild(data);
            Element books = doc.createElement("dc:books");
            classification.appendChild(books);

            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sampledb", "root", "8962");
            System.out.println("DB 연결 완료");
            stmt = conn.createStatement();

            stmt.executeUpdate("use verbal_violence;");
            System.out.println("테이블 변경");

            int i=0;
            while(i<82498) {
                System.out.println((i+1)+"/82498");
                i++;
                ResultSet sentences = stmt.executeQuery("select * from sentences where sentences_id = "+i+";");
                sentences.next();
                Element sen = doc.createElement("nif:sentence");
                data.appendChild(sen);

                //현재 행 문장 정보 다 뽑기
                String id = sentences.getString("sentences_id");
                String sentence = sentences.getString("sentence");

                Element text = doc.createElement("wikipedia:text");
                text.appendChild(doc.createTextNode(sentence));
                sen.appendChild(text);

                ResultSet category = stmt.executeQuery("select category_id from sentences_category where sentences_id = "+ id +";"); category.next();
                String category_id = category.getString("category_id");
                sen.setAttribute("sentences_id", id);

                Element information = doc.createElement("pmlp:information");
                sen.appendChild(information);
		} catch (Exception e) {
            System.out.println("예외 발생");
        } 
}

 

 내가 이 코드를 보고 감탄을 한게. 나는 DB에서 필요한 데이터를 모두 뽑는 메소드 하나, 그 데이터를 XML로 넣는 메소드를 만들었다. 그러나 오빠는 한 메소드에서 DB에서 뽑은 데이터를 바로 XML에 넣어서 불필요한 메모리 낭비를 막았다. 

 

 나는 오빠가 거의 신으로 보였다...

 


<xml 파일로 xsd 만들기>

정보 제공 : 싸가지 오빠

서포트 : 세윤탁

 

1. 온라인 변환기를 통해 xsd파일 만들기 

https://www.liquid-technologies.com/online-xml-to-xsd-converter

 

Free Online XML to XSD Converter

 

www.liquid-technologies.com

 

2. xml 문서 수정

당연한게도 xml 문서를 수정해야 한다.

 

 요 코드에서 14줄, 15줄을 추가해주면 된다. 

 

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="첫번째 xsd 파일 이름"

 

 이거 두 개 추가하는 건데 몇 시간을 헤맸다.후...


<xml valid>

 XML Copy Editor라는 툴을 아는가?

 

 xml 문서의 구조가 적절한지(여는 태그, 닫는 태그가 맞는지; well-formed) 문서가 유효한지(valid)한지 검사해주는 툴이다. 

 

 아마 이번 web프로그래밍 수업을 듣는 모든 분들의 골머리를 썩게 한 녀석일거다. 이 수업의 최종 발표 때는 완성된 xml이 valid하다는 것을 증명해야 하는데, 이 툴이 쉽게 valid를 안 주기 때문이다. 후. 

 

 그래서 온라인 valid 검증기를 사용할까 싶었는데, 세윤탁의 도움으로 다행히 valid를 통과했다. 

https://www.xmlvalidation.com/documentation

 

Documentation

An example If you would like to see how xmlvalidation.com works, but don't have an XML file to use for testing, you can use this example. First, paste or upload the XML file. You will then be prompted for the XSD file. When both are uploaded, the errors wi

www.xmlvalidation.com

 

1. xml과 xsd의 저장 위치를 같게 할 것.

2. 저장 경로에 한글이 없게 할 것

 진짜 너무 중요해서 한 번 더 말한다. 저장경로에는 한글이 없어야 한다. 이것도 valid가 너무 안 떠서 몇 시간을 절망해있었다. 나의 xml과 xsd의 저장 경로는 위 사진과 같았다. 

 

 이때 세윤탁이 내 컴퓨터에서는 valid가 안 뜨다가 다른 컴퓨터에서는 valid가 뜨는 경우가 있다고 해서. 지푸라기라도 잡는 심정으로 핑퐁오빠에게 파일을 보내주었다. 처음에는 오빠도 valid가 안 떴는데. 혹시나 해서 저장 경로를 C로 바꾸니 된다고 해서 알아낸 거다. 

3. xml에서 루트 네임 스페이스에 아래 코드를 추가해준다. 

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="첫번째 xsd 파일 이름"

 

 어여쁜 validㅜ

 


 사실 이 프로젝트 마감일이 내 생일(12월 6일)이었고, 친구들과 그 전날 부터 당일 새벽 5시까지 프로젝트를 했다. 그러다보니 자연스럽게 생일 축하도 받았지만 기쁘고 설레는 마음보다 당장 프로젝트를 제출하지 못할까봐 겁나는 마음이 더 컸다. 

 

 그리고 결국 새벽 4시가 되고 마지막 최종 ppt를 만들 때. 개강부터 지금까지 장장 3개월에 걸친 프로젝트가 드디어 끝났음에도 나는 담담했던 것 같다. 

 

 프로젝트에서 내가 맡은 작업 어디에도 누군가의 도움이 들어가지 않은 부분이 없다.

 

 한 학기가 끝나간다. 시험이 남긴 했지만 몇몇 교수님께서는 마지막 수업이라며 "한 학기동안 고생 많았다."라는 말씀을 하신다. 그 말씀들을 들으며 한 학기동안 나는 과연 무엇을 했고, 무엇이 남았는지에 관해 생각했다. 

 

 특히 이 프로젝트는 핑퐁 오빠의 도움이 컸다. 내가 이틀 가까이 머리 싸매던 코드를 오빠가 2시간 만에 만들었을 때. 나는 왜 이런 코드를 못 만들었지. 나는 왜 이렇게 코드를 짤 생각을 못 했지. 자괴감이 들었다. 

 

 비단 이 프로젝트 뿐만은 아니다. C언어, JAVA 수업의 프로젝트 최종 발표를 보면서. 아 좀 더 열심히 해볼 걸. 아 좀 더 간절하게 해볼 걸. 이런 생각만 들었다. 위의 자괴감은 말할 것도 없다. 또, 자바 프젝에서 못한 JDBC 연결을 DB/웹 프젝에서 핑퐁 오빠의 도움을 받아 연결했을 때. 내가 JDBC 연결을 못한 게 아니라 간절하게 안 했구나라는 자기혐오도 들었다.  

 

 나는 이번 학기가 도움 받기만 하고 내 손으로 일궈낸 것이 없다고 생각한다. 열심히 한다고 버릇처럼 말했는데 막상 열심히 한 것 같지 않다. 남는 공부를 하고 싶어서 연구실을 나왔는데 지금 나는 남는 공부를 하지 않고 있다. 

 

 물론 지금은 자괴감, 자기혐오가 아무 필요가 없다. 이미 다 끝난 일이다. 아무튼 먹먹하지만 이로써 모든 프로젝트가 끝이 났다. 가장 빡세다는 2학년 2학기 보낼 수 있도록 도와준 모든 분들에게 감사의 마음 전하며 

 

 이번 포스팅은 끝!