[Java] Xml를 파서로 xPath형식으로 읽어드리기


Development note/Java  2015. 2. 8. 01:32

안녕하세요.. 명월입니다.


이번 포스팅에서는 제목그대로 XmlParser를 이용해서 xml을 읽어드리는 것을 포스팅하겠습니다. 제가 소스를 작성하기 전에는 필요에 의해서 작성을 했는데. 작성으로 하고 나서 API를 찾아보니깐 xPatah로 읽어드리는 JAVA API가 있더군요..

실제 xPath로 읽어드리는 모듈을 만드시는 분들은 그 API를 사용하시고. 이 포스팅에서는 XML 파서를 이용하는 사람들에게 도움이 될까해서 포스팅을 시작하겠습니다.

먼저 클래스는 new로 선언하는 것이 아니라 Instance로 선언하겠습니다 이유는 생성자 관리 때문입니다.

초기화 시에는 DocumentBuilderFactory, Document 클래스를 이용해서 XML파일을 읽어드려 메모리에 올리겠습니다.


Document와 File의 경우는 멤버로 빼서 관리를 하고 각 타입 별로 enum을 선언하였습니다. Enum의 경우는

먼저 NODE,ATTRIBUTE,LIST 타입이 있는데..

xPath의 경우는 여러 형태가 있지만 제가 쓰는 경우는 @xxx, XXX[5], AA 형식의 Attirbute, 배열, 일반 노드 형식이 되겠습니다. 자세한 예제 내용은 프로그램을 완성 후에 예제로 확인하겠습니다.

먼저 생각하는 클래스의 형태는 외부에서 getValue로 들어오겠습니다.

예로 getValue(“/Test/A1/B1”,String.class) 이런 형태의 값이 되겠네요.

들어오게 되면 본 소스의 NodeFind함수가 불려지게 됩니다.

NodeFind만의 소스만 봤을 때는 각 Path를 splite으로 나눈 뒤에 각 path의 요소를 확인 합니다. Node인지 배열인지 Attribute인지 확인하는 것이지요.. 그 각 요소를 확인 후에 getElementsByTagName 함수와 Item 함수를 이용해서 탐색을 시작하는 것입니다.

import java.io.File;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XMLReader{
  
  private Document xmlDocment = null;
  private File file = null;
  protected Document getDocument(){
    return xmlDocment;
  }
  protected void setDocument(Document xmlDocment){
    this.xmlDocment = xmlDocment;
  }
  protected File getFile(){
    return this.file;
  }
  protected void setFile(String filepath){
    file = new File(filepath);
  }
  protected enum NodeType{
    NODE,
    ATTRIBUTE,
    LIST,
    
    RET_RESULT,
    RET_COUNT,
    RET_LISTRESULT
  }
  public static XMLReader getInstance(String path) throws Exception{
    return new XMLReader(path);
  }
  protected XMLReader(){ }
  protected XMLReader(String path) throws Exception{ 
    initialize(path);
  }
  protected void initialize(String path)throws Exception{
    setFile(path);
    DocumentBuilderFactory docBuildFact = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuild = docBuildFact.newDocumentBuilder();
    setDocument(docBuild.parse(getFile()));
  }
  protected Object NodeFind(String xpath,NodeType flowtype) throws Exception{
    NodeList nodeList = null;
    Element element = null;
    getDocument().getDocumentElement().normalize();
    ArrayList<String> pathNode = PathSplite(xpath);
    NodeType type = null;
    int listIndex = 0;
    String pNodeName = "";
    for(int i=0 ; i < pathNode.size() ; i++){
      type = NodeTypeCheck(pathNode.get(i));
      if(type.equals(NodeType.NODE) || type.equals(NodeType.LIST)){
        pNodeName = pathNode.get(i);
        if(type.equals(NodeType.NODE)){
          listIndex = 0;
          if(  (flowtype == NodeType.RET_COUNT || flowtype==NodeType.RET_LISTRESULT) 
              && i == pathNode.size() -1)
            break;
        }else{
          try{
            int sPos = pNodeName.indexOf("[")+1;
            int ePos = pNodeName.indexOf("]");
            listIndex = Integer.valueOf(pNodeName.substring(sPos,ePos)) - 1;
            pNodeName = pNodeName.substring(0,sPos-1);
            if(i == pathNode.size() -1) break;
          }catch(Exception e){
            throw new Exception("Pathの表現が非性格です。ErrorCode : FE_NodeFind - 1");
          }
        }
        
        if(element == null)  {
          nodeList = getDocument().getElementsByTagName(pNodeName);
        }else{
          nodeList = element.getElementsByTagName(pNodeName);
        }
        if(nodeList.getLength() > 0){
          element = (Element)nodeList.item(listIndex);
        }else{
          throw new Exception("Pathの表現が非性格です。ErrorCode : FE_NodeFind - 2");
        }
      }
    }
    if(type.equals(NodeType.NODE) ||type.equals(NodeType.LIST)){
      if(element.getChildNodes().getLength() > 0){
        nodeList = element.getChildNodes();
        if(nodeList.getLength() <= 1){
          Node node = (Node)nodeList.item(0);
          if(NodeType.RET_RESULT == flowtype){
            return node.getNodeValue();
          }else{
            return 1;
          }
        }else{
          ArrayList<String> pRet = new ArrayList<String>();
          nodeList = element.getElementsByTagName(pNodeName);
          if(NodeType.RET_LISTRESULT == flowtype){
            for(int i=0;i<nodeList.getLength();i++){
              element = (Element)nodeList.item(i);
              if(element.getChildNodes().getLength() <= 1){
                Node node = (Node)element.getChildNodes().item(0);
                pRet.add(node.getNodeValue());
              }
            }
            return pRet;
          }else{
            return nodeList.getLength();
          }
        }
      }else{
        throw new Exception("動作エラー。ErrorCode : FE_NodeFind");
      }
    }else if(type.equals(NodeType.ATTRIBUTE)){
      if(NodeType.RET_RESULT == flowtype){
        String attrName = pathNode.get(pathNode.size()-1).substring(1);
        return element.getAttribute(attrName);
      }
    }
    return null;
  }
  protected int getCountChildNode(String xpath,String childenode){
    try{
      return Integer.valueOf(NodeFind(xpath+"/"+childenode,NodeType.RET_COUNT).toString());
    }catch(Exception e){
      throw new ClassCastException("ノードタイプが合わないです。");
    }
  }
  protected NodeType NodeTypeCheck(String nodeName){
    if(nodeName.indexOf("@") >= 0){
      return NodeType.ATTRIBUTE;
    }else if(nodeName.indexOf("[") >= 0 && nodeName.indexOf("]") >= 0){
      return NodeType.LIST;
    }else{
      return NodeType.NODE;
    }
  }
  protected ArrayList<String> PathSplite(String path) throws Exception{
    String[] pathNode = path.split("/");
    if(pathNode.length <= 1){
      throw new Exception("Pathの表現が非性格です。- ErrorCode : PathSplite");
    }
    ArrayList<String> ret = new ArrayList<String>();
    for(int i=1 ; i < pathNode.length ; i++){
      ret.add(pathNode[i]);
    }
    return ret;
  }
  @SuppressWarnings("rawtypes")
  public Object getValue(String xpath,Class type) throws ClassCastException,Exception{
    try{
      if(type == String.class){
        return NodeFind(xpath,NodeType.RET_RESULT);
      }else if(type == ArrayList.class){
        return NodeFind(xpath,NodeType.RET_LISTRESULT);
      }else{
        throw new ClassCastException();
      }
    }catch(ClassCastException e){
      throw new ClassCastException("「" + type.getName() +"」タイプに返却できません。- ErrorCode : get");
    }
  }
}

결과 확인하겠습니다.

원하는 결과를 얻었습니다

sample.xml

XMLReader.java