안주꺼리 2010/03/22 10:02
  • 글라스우드 - 난연, 무독성, 방부, 방충, 치수안정성, 강도, 내구성 등 탁월한 성능을 발휘하도록 만든 불용성 목재
  • - XML로 데이터 통신하는 경우가 많은 상황입니다.
        따라서 XML을 파싱하는 함수는 거의 필수적인 라이브러리가 되었습니다.
        아래 함수는 XmlObjectToArray 함수로써, simplexml_load_string를 사용하였습니다.
      ( 고로 PHP5 이상이어야만 합니다. )
     
      - 기능
        xml string을 PHP5 기본제공함수인 simplexml_load_string으로 Object로 바꾼 객체를
        사용하기 편하도록 Array로 변환
       
      - 제한사항
        앞서 언급했지만, PHP5를 사용할수 있는 환경이어야 합니다. ( simplexml_load_string )
        캐릭터셋은 EUC-KR 아니면 UTF-8이라 가정하에 처리하였습니다.
        ( 원래 이러면 안되지만, 적절히 수정하셔서 쓰시길.. )


      - 사용법 유의사항
        XML의 경우 중복된 Element 들이 있는 경우는 따로 그 엘리먼트를 기억하여 인자로 배열로서 넘겨주어야 합니다.
        이는 simplexml_load_string 이라는 함수 자체가 object를 단수와 복수를 다른 포맷으로 전달하여 처리의 일관성을 보장하지 못하여 생기는 문제를 해결하기 위해 부득이하게 사용하게 되었습니다.
        나머지는 직접 사용해보시면 쉽게 이해가 되실것이라 생각됩니다.

      - 샘플 소스
    <?php
        
        function getHttpContents( $sUrl, $iTimeout = 5, $bHeader = false ) {
                $hCurl = curl_init();
                curl_setopt( $hCurl, CURLOPT_URL, $sUrl );
                curl_setopt( $hCurl, CURLOPT_TIMEOUT, $iTimeout );
                curl_setopt( $hCurl, CURLOPT_RETURNTRANSFER, 1 );
                if ( $bHeader == true ) {
                    curl_setopt( $hCurl, CURLOPT_HEADER, 1 );
                }
                $sResult = curl_exec( $hCurl );
                curl_close( $hCurl );
                return $sResult;
        }



        function XMLObjectToArray2( &$objSource, $arrMultiKey = array(), $bUTF8 = false ) {

            if ( is_object( $objSource ) ) {
                $array = array();
                if ( is_object( $objSource->attributes() ) ) {
                    foreach( $objSource->attributes() as $k => $v ) {
                        $array[ '@attributes' ][ $k ] = ( $bUTF8 == false ) ? iconv( 'UTF-8', 'EUC-KR', (string)$v ) : (string)$v;
                    }
                }
                foreach ( $objSource as $key => $value ) {
                    if ( (is_object($value) ) && ( count( $value ) > 0 ) ) {
                        if ( in_array( $key, $arrMultiKey ) ) {
                            $array[ $key ][] = XMLObjectToArray2( $value, $arrMultiKey, $bUTF8 );
                        }
                        else {
                            $array[ $key ] = XMLObjectToArray2( $value, $arrMultiKey, $bUTF8 );
                        }
                    }
                    else if ( is_object($value) ) {
                        # 맨 마지막 Depth의 Element는 항상 한개씩 빼온다.
                        $sValue = ( $bUTF8 == false ) ? iconv( 'UTF-8', 'EUC-KR', ( string )$value[ 0 ] ) : ( string )$value[ 0 ];
                        if ( in_array( $key, $arrMultiKey ) ) {
                            $array[$key][] = $sValue;
                        }
                        else $array[ $key ] = $sValue;
                    }
                    else {
                        if ( is_array( $value ) ) {
                            $array[ $key ] = $value;
                        }
                        else {
                            $array[ $key ] = ( $bUTF8 == false ) ? iconv( 'UTF-8', 'EUC-KR', ( string )$value ) : ( string )$value;
                        }
                    }
                }
                return $array;
            }
            return $objSource;
        }


        $sUrl = 'http://xxxxxx/?xxxxx';
        $sHttpContents = getHttpContents( $sUrl );

        $objDom = simplexml_load_string( $sHttpContents );

        $arrData = XMLObjectToArray2( $objDom,  array( 'address', 'index' ) );

    ?>
    2010/03/22 10:02 2010/03/22 10:02
    이 글의 관련글

    Trackback Address : http://www.1go.co.kr/blog/trackback/3442

    [로그인][오픈아이디란?]
    안주꺼리 2010/03/22 09:51
  • 글라스우드 - 난연, 무독성, 방부, 방충, 치수안정성, 강도, 내구성 등 탁월한 성능을 발휘하도록 만든 불용성 목재
  • <?php
        function random_code($type="D", $code_num=32){
            $letter = NULL;
            if($type == "A" or $type == "D") $letter = "azertyuiopqsdfghjklmwxcvbn";
            if($type == "B" or $type == "D") $letter .= "AZERTYUIOPQSDFGHJKLMWXCVBN";
            if($type == "C" or $type == "D") $letter .= "0123456789";

            $max = strlen($letter)-1;
            $code = null;
            for($i=0; $i < $code_num; $i++) $code .= $letter{mt_rand(0, $max)};
            
            return $code;
            }
            
        /*URL 검사기
        */
        function is_url($url){
            if(preg_match("[^http://|^https://|^ftp://]", $url)){
                $info = parse_url($url);
                $info['type'] = "internet";
                return $info;
            }
            elseif(preg_match("[/|\\\\|\.+([A-Za-z])]", $url)){
                $info = pathinfo($url);
                $info['type'] = "localhost";
                return $info;
            }
            else return FALSE;
            //if(preg_match($pattern, $url)) return TRUE;
            //else return FALSE;
        }
        class domXml{        
            /*
             * domXML 클래스 아주 중요한 클래스들이다.
             * 사용법:
             * 1번 방법
             * $this->{'data'} = "<data><title></title></data>";
             * 위에 처럼하면 data로 호출시 위에 데이터가 들은 DOM객체를 반환한다.
             *
             * 2번 방법
             * $this->{'http://babo.net/나XML.xml'};
             * 위에 처럼하면 http://babo.net/wow.xml로 호출시 해당 xml의 데이터가 들은 DOM객체를 반환
             * 3번방법
             * $this->{'wow2.xml'} = "<data><title></title></data>";
             * XML 확장자를 가진 이름이면 주소가 없으면 해당 자료를을 넣은 데이터의 DOM을 반환한다.
             * !!주의 할것은 이미 파일이 있으면 에러가 걸리니 주의 해라.
             *
             * !!!!이미 있는 파일 변조하고 다시 저장시.
             * $this->{'나XML.xml'} = $this->{'나XML.xml'}->firstChild->ownerDocument;
             *
             * 이렇게 다시 Document를 넣으면 종료 될때 자동 저장된다.
             * 주의:: 같은 DOM객체여야 한다. 서로 틀린 DOM 경우 전혀 안된다. 프로토콜로 시작하는 이름은 에러가 걸리니 주의 해라.
             *
             * 이하 메소드 설명 귀찮아서 안함.
            */
            private  $version, $encoding;        
            private  $stand_by_save = array();
            private Static $xml_key = array(), $node = array();
            
            private $nowDom;
            
            private Static $classDomXml  = false;
            
            public Static function classLoad($version="1.0", $encoding="utf-8", $load = true){
                if(!domXml::$classDomXml and $load) return domXml::$classDomXml  = new domXml($version, $encoding);
                else return domXml::$classDomXml;
            }
            
            function __construct($version, $encoding){
                $this->version = $version;
                $this->encoding = $encoding;
            }
            
            /********************
            1번 일반키
            2번 로컬 파일
            3번 원격지 파일
            ********************/
            final private function info_check($key){
                $info = is_url($key);
                switch($info['type']){
                    case "internet":
                        return  $info;
                    break;
                    case "localhost":
                        $info['file_exists'] = file_exists($key);
                        return  $info;
                    break;
                    default:
                        $info['type'] = "key";
                        return $info;
                    break;
                }
            }

            final private function is_info($key){
                if(isset($xml_key[$key])) return $xml_key[$key];
                else return self::$xml_key[$key] = $this->info_check($key);
            }
            
            //호출시
            //키가 존재하면 반환하고 아니면 로드을 호출한다.
            final public function &__get($key){
                
                switch(isset(self::$node[$key])){
                    case(TRUE):
                        return self::$node[$key];
                    break;
                    case(FALSE):
                                            if($dom = $this->load($key)) self::$node[$key] = $dom;
                                            return $dom;
                    break;
                }
            }
            
            //입력시
            //키가 존재 안 하면 미리 세팅한다고 판단 세이브 평션을 호출한다.
            //키가 존재 하면 저장한다고 판단 세이브를 한다.랜덤 코드를 비교해서 같으면 저장 아니면 거부 한다.
            final public function __set($key, $var){
                switch(isset(self::$node[$key])){
                    case(FALSE):
                        $node = $this->save($key, $var);
                        if($node) {
                            self::$node[$key] = $node;
                        }
                    break;
                    case(TRUE):
                        $info = $this->info_check($key);
                        if(($info['type'] == "localhost" and $info['file_exists'])and $this->check_code(self::$node[$key]) == $this->check_code($var)){
                            $this->stand_by_save($key);
                            self::$node[$key] = $var;
                        }
                    break;
                }
            }

            final private function check_code($node){
                return $node->documentElement->ownerDocument->check_code;
            }

            final private function load($var){
                $info = $this->is_info($var);
                $dom = new \DOMDocument($this->version, $this->encoding);
                $dom->preserveWhiteSpace = false;
                $dom->formatOutput = true;
                //그냥 일반키면 거부값 보내기
                if($info['type'] == "key"){
                    unset($dom);
                    return false;
                }
                //로컬 파일이면 이때 파일이 있으면 로드하고 없으면 일반키 처럼 처리.
                elseif($info['type'] == "localhost"){
                    if($info['file_exists']) $dom->load($var);
                    else return false;
                }
                //리모트호스트면 세이브가 불가능함.
                elseif($info['type'] == "internet") $dom->load($var);

                $dom->check_code = random_code("C", 10);
                return $dom;
            }

            final private function save($key, $var){
                $info = $this->is_info($key);
                //그냥 일반키면 넘어간다.
                //로컬 파일이면 이때 파일이 있으면 에러를 보낸다.
                if($info['type'] == "localhost"){
                    if($info['file_exists']) return false;
                    else $this->stand_by_save($key);
                }
                //원격지면면 에러를 보낸다,
                elseif($info['type'] == "internet") return false;

                $dom = new DOMDocument($this->version, $this->encoding);
                $dom->preserveWhiteSpace = false;
                $dom->loadxml("<?xml version=\"".$this->version."\" encoding=\"".$this->encoding."\" ?>".$var);
                $dom->check_code = random_code("C", 10);
                $dom->formatOutput = TRUE;
                
                return $dom;
            }

            //작업을 완료되면 자동으로 세이브함
            final function __destruct(){
                foreach($this->stand_by_save as $key => $var) $this->completion($key);
            }
            
            //클래스 소멸시 자동으로 저장할 목록 저장.
            final private function stand_by_save($key){
                $this->stand_by_save[$key]=$key;
            }
            
            //저장하기.
            /*절대 경로를 넣은 이유가 클래스가 unset없이
            소멸자를 호출시 이상한 곳에 파일을 만들기에 넣는다.*/
            final public function completion($key){
                self::$node[$key]->save($key);
            }
            
            
        }

    ?>


    제가 쓰고 있는 XML로드 클래스 입니다.
    위에 주석문에도 있지만 소스가 보기에는 난잡해서 여기다 다시 적어 드려요.
    그리고 아직 몇가지 문제점이 보이는데 제가 쓰는대 아무 문제가 없는 관계로;;
    차후에 필요하면 고쳐서 다시 올릴게요.
    (참고로 소스가 난잡하게 보인것은 tab을 써서 그래요.)
    $test = new xmlDom();

    첫번째 방법으로 일반키 적용으로
    $test->{'data'} ="<data></data>";
    이렇게 하면 $test->{'data'}에 <data></data>적용된 DOMDocument가
    들어가게 됩니다.  부를떄는 $test->{'data'} 이렇게 부르면 됩니다.
    해당 자료가 없으면 FALSE 값을 내놓습니다.

    원격지 파일 부르기.
    두번째는 $test->{'http://aa.kr/s.xml'}로 부르면 역시나 DOMDocument이 들어가게 됩니다.
    아 여기서 $dom = $test->{'http://aa.kr/s.xml'} 이런분들이 간혹 존재 할걸로 예상 되는데 이러면 절대 안됩니다.
    $test->{'http://aa.kr/s.xml'};
    $dom = $test->{'http://aa.kr/s.xml'};
    이렇게 하셔야 합니다. 한번 로드 된것은 Static에 저장 되기에 여러번 로드해도 문제 없답니다.

    로컬 파일 부르기.
    로컬 파일은 역시나 $test->{'/home/www/s.xml'} 이렇게 하시면 됩니다.
    로컬파일은 세이브가 지원 되는데. 여기서 문제가 있습니다.
    로드만 하면 문제가 없습니다. 세이브 쓴다면 하면 꼭 절대 경로로 파일을 불러주세요.
    안 그러면 세이브 할때 데이터가 아파치 경로에다 만들어 버립니다.
    왜 그런지는 나도 모릅니다.
    세이브 방법은
    $this->{'/home/www/s.xml'} = $this->{'/home/www/s.xml'}->firstChild->ownerDocument;

    이렇게 하시면 됩니다.
    이후 절대 적인 관심이나 오타 그리고 지적좀 알려주세요.
    2010/03/22 09:51 2010/03/22 09:51
    이 글의 관련글

    Trackback Address : http://www.1go.co.kr/blog/trackback/3439

    [로그인][오픈아이디란?]
    안주꺼리 2010/01/22 22:04
  • 글라스우드 - 난연, 무독성, 방부, 방충, 치수안정성, 강도, 내구성 등 탁월한 성능을 발휘하도록 만든 불용성 목재
  • XML 테스트는 XML문서를 어떻게 만들고 어떻게 화면에 표출하는가에 대한 예를 보기위해 공부하면서 몇자 적어본다.

    본 예제는 php를 기준으로 하며 php5에 갖고 있는 libxml2 인 xml pasher를 기준으로 설명해본다.

    xml 문서 작성

    XML의 시작은 아래처럼 구문이 들어가야만 XML이 시작된다고 보면된다.
    <?xml version='1.0' standalone='yes'?>

    XML 문서는 html 문서와 유사한면이 있기도 하다. html 문서 작성하듯 xml 문서 역시 시작과 끝이 있다.

    <구분자> 데이터 </구분자>
    or
    <구분자 type="type 데이터"> 데이터 </구분자>

    이렇게 "구분자"로 시작해 끝낼때는 /로 시작하는 "구분자"를 넣어주면 된다.

    이 데이터를 처리하는 몇가지 function을 살펴보자.

    xml 파일을 읽어들이기
    $xml=simplexml_load_file("filename");

    PHP내의 xml string을 읽어들이기
    $xml=SimpleXMLElement($xml_string);

    구분자의 갯수 얻기
    $p_cnt=count($xml->구분자);

    xml 내용을 화면에 출력하기(array형식에 맞춰)
    print_r($xml)

    구분자의 내용을 출력하기
    $xml->구분자->sub_구분자
    or
    $xml->구분자->{'sub_구분자'}

    {' '}을 쓰는경우는 구분자만 쓸때 기호 에러(특수기호때문에)가 나면 이것으로 묶어서 구분자임을 알려준다.

    구분자를 type 등으로 분류를 해줄경우 type의 형태를 출력
    $xml->구분자['type'];
    "type_데이터"가 출력됨.
    이런 형태의 구분자의 데이터 출력
    "$xml->구분자['type']"이 원하는 것일경우의 "$xml->구분자"가 데이터 출력됨.

    linux 경로처럼 xml data tree 구조를 path로 사용한다.
    $xml->xpath(/구분자1/구분자2/구분자3);  // 절대 경로
    $xml->xpath(구분자2/구분자3); //상대경로




    간단한 예로 책에 대해 보면

    <?xml version='1.0' standalone='yes'?>
    <library>
       
    <book>
           
    <name>손오공</name>
           
    <price>1000</price>
           
    <unit></unit>
           
    <date type="년">2009</date>
           
    <date type="월">10</date>
           
    <date type="일">4</date>
         
    </book>
       
    <book>
           
    <name>이상한나라</name>
           
    <price>1</price>
           
    <unit>만원</unit>
           
    <date type="년">2009</date>
           
    <date type="월">10</date>
           
    <date type="일">4</date>
         
    </book>
    </library>

    xml 데이터를 읽어들이는것은 아래처럼 simplexml_load_file과 같은 Class로 읽어들인다.

    $xml = simplexml_load_file('ex.xml');
    print_r
    ($xml); // xml의 구조를 화면에 출력한다.
    echo
    "<br><br><hr><br>";
    echo $xml
    ->book[1]->{'name'}; //구분자 "name"의 값을 출력한다.

    //책 "손오공"의 date를 년월일을 출력한다.
    foreach ($xml->book[0]->date as $date) {
       
    switch((string) $date['type']) {
       
    case '년':
           echo $date
    , '년';
           
    break;
       
    case '월':
           echo $date
    , '월';
           
    break;
       
    case '일':
           echo $date
    , '일';
           
    break;
       
    }
    }

    간단한 예로 위에서 했던것을 php속의 string으로 넣어보자.

    <?php
    $xmlstr
    = <<<XML
    <?xml version='1.0' standalone='yes'?>
    <library>
       
    <book>
           
    <name>손오공</name>
           
    <price>1000</price>
           
    <unit></unit>
           
    <date type="년">2009</date>
           
    <date type="월">10</date>
           
    <date type="일">4</date>
         
    </book>
       
    <book>
           
    <name>이상한나라</name>
           
    <price>1</price>
           
    <unit>만원</unit>
           
    <date type="년">2009</date>
           
    <date type="월">10</date>
           
    <date type="일">4</date>
         
    </book>
    </library>
    XML;
    ?>

    이렇게 만들고 아래처럼 불러들여 사용한다.

    <?php
    include
    'ex.php';
     
    $xml
    = new SimpleXMLElement($xmlstr);
    //xml 코드들
    ?>


    xpath 예제

    <?
    $xml
    =simplexml_load_file('test.xml');
    $groups
    =Array(a,b,c,d);

    for($z=0;$z<sizeof($groups);$z++) {
       $result
    =$xml->xpath("a/$groups[$z]/name");
       
    while(list( ,$node) =each($result)) {
           $result2
    =$xml->xpath("a/$groups[$z]/$node");
           
    while(list( ,$node2)=each($result2)) {
              echo
    "a/$groups[$z]/$node/".$node2['type']. ":". $node2."<br>";
           
    }
       
    }
    }
    ?>
    2010/01/22 22:04 2010/01/22 22:04
    이 글의 관련글

    Trackback Address : http://www.1go.co.kr/blog/trackback/3330

    [로그인][오픈아이디란?]