2005년 10월 27일 목요일

[8.31대책 피해가는 절세안 上] 증여가 절세안 될까?

8.31대책 이후 시중에는 갖은 꼼수가 난무하고 있다. 하지만 회피수단에 들이는 품이나 법적 절차 비용 등을 생각할 때 나중에 보면 별반 차이가 없거나 차후 추징을 당할 우려가 있는 탈법 행위들인 경우가 많은게 사실이다. 스피드뱅크는 이번 기회에 시장에 흘러다니는 절세안들을 알아 보고 좀 더 정확한 정보를 제공하는 자리를 마련하였다.
 
증여가 회피책이 될 수 있나?

8.31대책의 가장 큰 핵심은 1가구2주택자의 늘어난 세금부담이라 할 수 있다. 따라서 세금회피책도 이 부분에 집중되고 있는데 가장 흔하게 들을 수 있는 얘기는 증여하면 고액의 양도세를 피할 수 있냐? 라는 물음 이다.

원칙적으로 증여세 산정기준은 시가로 되어 있으나 무상의 성격인 증여의 특성상 시가를 산정하기 어렵기 때문에 주택의 경우 기준시가를 보충적 평가가액으로 적용하고 있는 실정이다. 다음의 표는 중대평형, 재건축단지, 강북아파트를 비교 조사한 것으로 중대평형과 재건축의 경우 오름폭이 큰 단지와 적은 단지를 대조하였으며 증여의 경우 전세 낀 방법이 함께 회자되고 있어 전세 낀 증여가 얼마나 효과가 있는지도 비교해 보았다.

*실제 단지를 샘플링 하였으나 지역적 사정을 고려하여 실단지명을 생략하였다.  
 전세 낀 증여시 양도세 비교 = 양도세 - (전세가 공제한 증여세 + 전세가 해당 양도세 및 취.등록세) ; (-)의 경우 전세 낀 증여보다 양도세가 유리한 경우임.

 
샘플링 조사의 결론부터 얘기하면, 양도세와 증여세만을 단순 비교시 증여의 방법으로 절세가 가능한 경우는 주택투기지역에 위치한 아파트로 기준시가 2억 이하 이면서 양도차익이 8000만원 이상 난 경우 라고 할 수 있었다. 반면에 실거래가 기준이 아닌 강북 35평의 경우 양도세가 `0`인 경우로 증여를 택할 이유는 없어 보인다. 
중대평형(1)(2)의 경우 기준시가 자체가 덩치가 커서 웬만하면 증여를 생각할 수 없는 경우이나 분당의 중대평형(1) 처럼 양도차익이 크게 발생한 경우 증여가 2000여만원 정도 유리하고 전세 낀 증여를 고려 한다면 전세금에 대해 양도세,취등록세가 부과되는 비용을 감안하더라도 4600여 만원 정도의 이득이 남는 것을 볼 수 있었다. 강남 중대평형(2)의 경우에는 단순 증여시 양도세 보다 1억여원 더 증여세를 내야 해 양도세를 내는 편이 훨씬 나아 보였으나 전세 낀 증여를 택할 경우 83만원 정도 유리함을 볼 수 있었다. 차익이 많이 남지 않는 경우로 장기 보유를 선택하였을 경우에만 생각해 볼 만한 방법이라 여겨진다.

재건축단지들의 경우 기준시가가 낮게 되어 있는데다 그동안 오름폭이 컸던 만큼 증여를 고려해 볼 만한 대표적 경우라고 할 수 있는데 그렇다 하더라도 각자 처한 상황에 따라 결과는 크게 달라졌다. 강남재건축 (1)의 경우 양도세 보다는 증여를 선택하는 측이 600만원 정도 남는 장사이고 전세 낀 증여가 이루어질 경우 1400여만원으로 폭이 커짐을 볼 수 있었는데 강남재건축(2)의 경우에는 증여 보다는 양도세가 3000여만원 더 절약 되는 방법이고 전세 낀 증여를 하더라도 1200만원 가량 손해를 보이고 있었다. 워낙 다른 변수들이 많아서 정확히 선을 그을만한 기준은 없지만 기준시가 대비 양도차익이 45%정도 이상 나는 경우에 증여의 방법이 납세자에게 더 유리하다고 할 수 있겠다. 참고로 샘플링에 동원된 강남재건축(1)의 기준시가대비 양도차익율은 50.1%이고 강남재건축(2)의 기준시가대비 양도차익율은 26.9%이다.

산출된 증여세는 증여세 신고기한 내(증여일로부터 3개월) 신고시 10% 추가감세 되므로 증여가 유리한 분당 중대평형(1)과 강남 재건축(1)의 증여시 이득액은 위의 산출금액보다 더 커질 수 있다. 또한 샘플의 경우 보유기간이 2년 지난 것으로 가정하였으므로 1년 미만 보유인 경우 50%, 1가구3주택 이상 자는 60%의 높은 양도세율이 부과됨을 고려하면 표와는 훨씬 다른 결과가 나올 수 있다는 것을  감안해야 한다.

1가구1주택 비과세를 활용하라

양도세와 증여세의 비교는 양도세를 내야 할 수 밖에 없는 경우를 가정한 것으로 양도세를 내지 않아도 된다면 굳이 증여세를 뽑아 비교해 보는 수고를 하지 않아도 된다. 시중 소문의 대다수도 1가구1주택 비과세와 연결되어 있는 측면이 많아 소문의 진위 여부를 판단하는데는 1가구1주택 비과세를 정확히 아는 것이 도움이 될 듯 싶다.

원칙적으로 1가구가 양도일 현재 하나의 주택만을 보유하고 있고, 이에 대한 보유기간이 3년 이상이라면 양도소득세는 비과세 된다. 다만 서울,과천 및 5대 신도시(분당,일산,평촌,중동,산본)등 일부 지역에 소재하는 주택의 경우는 3년 이상 보유기간에 2년 이상 거주기간을 갖춰야만 비과세 조건이 충족된다. 또한 양도가액 6억원 이상의 고가주택의 경우 실거래가로 과세되므로 비과세에서 제외된다. 

2주택 중과세 해당여부 판단기준은 서울. 광역시, 경기도의 모든 주택과 기타지역의 국세청 기준시가 기준 3억원 초과주택이 그 대상이다. 하지만 광역시 군지역, 경기도 도농 복합시의 읍,면 지역 및 기타 도 지역의 기준시가 3억원 이하 주택은 보유하더라도 1가구2주택 중과세 적용에는 해당 되지 않는다.

보유기간에 있어서도 해외이주 등 부득이한 이유가 있으면 보유기간 3년을 요구하지 않는데 다음과 같은 경우들이다. ①해외이주 또는 1년 이상 계속하여 국외거주를 필요로 하는 취학, 근무상의 형편으로 세대전원이 출국하는 경우,②5년 이상 거주한 임대주택법상의 건설임대주택을 취득 등기하여 양도하는 경우,③1년 이상 거주하였으나 취학,이직 등 부득이한 사정으로 3년 보유기간을 채우지 못한 채 세대전원이 다른 시,군으로 거주 이전하는 경우 등

1가구2주택자는 먼저 양도하는 주택에 양도소득세가 과세됨이 원칙이다. 하지만 부득이하게 2주택자가 되는 경우를 구제하기 위해 여러 예외를 두고 있는데, 먼저 신규 주택 취득으로 인한 일시적 2주택자의 경우를 들 수 있다. 이 경우 새로운 주택을 취득한 때로부터 1년 이내에 주택을 처분할 경우 비과세 된다. 단 이전 주택이 1가구1주택 비과세 요건을 충족하였음을 전제로 한다.

상속을 받아 2주택이 된 경우에도 어떤 주택을 처분하는가에 따라 적용기준이 달라지는데 기존주택을 먼저 처분하는 경우 상속주택이 있더라도 1가구1주택 비과세 요건을 갖췄다면 비과세 되지만 상속 받은 주택을 먼저 처분하는 경우에는 양도세가 과세되는 점을 주의해야 한다.

1가구1주택자가 1주택을 보유한 직계존속을 동거봉양하기 위하여 세대를 합침에 따라 2주택이 된 경우, 합가한 날부터 2년 이내에 먼저 양도하는 주택은 1가구1주택 비과세를 적용 받을 수 있다. 1주택자가 다른 1주택자와 혼인하여 2주택이 된 경우에도 혼인일로부터 2년 이내에 먼저 양도하는 주택의 경우에도 마찬가지이다.

일단 예전에 1가구 3주택이상 보유자 중과대상에서 제외되던 주택들이 8.31대책 이후에도 제외 대상이다. 열거하면 (ㄱ) 장기임대사업용주택으로 일정기간 임대후 양도하는 주택,(ㄴ)종업원에게 10년이상 무상으로 제공한 주택(장기사원용 주택),(ㄷ)상속받은 주택으로서 상속일부터 5년이 경과되지 아니한 것,단 피상속인의 상속주택이 2개 이상인 경우 피상속인의 소유기간이 가장 긴 주택만 해당,(ㄹ)문화재보호법에 의한 문화재 주택,(ㅁ)저당권 실행이나 채권을 변제 받기 위해 취득한 주택으로서 재정경제부령이 정하는 주택 등이다.

1가구원중 일부가 근무상 형편으로 다른 시,군에 이전하고 해당 시,군의 주택을 취득하였다면 1년 이상 거주하고 당해 사유가 해소된 날로부터 3년 이내에만 양도한다면 1주택이 지켜진다. 주택의 소유권에 관한 소송이 진행중인 경우이거나 소송의 결과에 따라 취득한 주택의 경우 소유권 확정판결일로부터 3년 동안 주택 수 산정이 유보된다.

수도권,광역시 주택이라 하더라도 기준시가 1억원 이하 주택의 경우 1주택 산정에서 빠진다. 그러나 재개발,재건축 주택은 제외되므로 유의해야 한다.

무소불위의 혜택 조세제한특례법

1가구1주택 비과세 혜택의 예외적 경우는 많은 매매 유형 가운데 극히 일부일 수 있는 까다로운 조건들을 내세우고 있다. 반면에 시기를 잘 잡은 행운아들이 있다. 이들은 조세특례제한법상 조건, 기한에 상관없이 양도세 비과세부터 상당한 감세혜택까지 딱 한번은 이러한 혜택을 사용할 수 있는 선택 받은 자들이라고 할 수 있는데 다음과 같다.

우선 임대 주택자들의 경우로 86년1월1일부터 2000년12월31일까지 신축주택을 5호 이상 임대한 임대사업자가 5년 이상 임대 후 양도할 경우 양도세가 50% 면제되고 10년이상 임대시에는 100% 면제된다. 또 다른 경우로는 99년8월20일부터 2001년12월31일까지 건설되거나 분양된 주택을 2호이상 임대한 임대사업자가 5년이상 임대 후 양도한 경우 양도세가 완전 감면된다. 앞의 두 경우 모두 국민주택에 한정되는 제한이 있다.

또 다른 사안은 미분양의 경우인데 95년10월31일 현재 미분양주택을 97년까지 취득한 경우 또는 98년2월28일 현재 미분양주택을 98년내 취득한 경우 종소과세나 양도세 20% 과세중 하나를 선택할 수 있는 혜택이 있다.

마지막으로 가장 큰 행운을 부여 잡은 사람들을 들 수 있는데 (ㄱ)98년5월22일에서 99년6월30일 분양물을 취득한 경우와 (ㄴ)01년5월23일부터 03년6월30일까지의 분양물을 취득한 자들로 취득 후 5년내 양도시 양도소득이 전액 면제되고 취득 5년이후 양도시 5년간 발생소득에 한해서는 양도소득을 면제한다. 단, (ㄱ)의 경우 고급주택(전용면적 50평이상,기준시가 5억원 초과)이 제외되고, (ㄴ)의 경우에는 고가주택(6억원 초과)이 제외 되며 서울,과천,5대 신도시 지역은 02년12월31일까지로 한정하고 있다.

이들이 얼마만큼 운이 좋은지는 다음의 두가지 예시를 보면 알 수 있다. 2001년9월에 분양한 강남의 A아파트 41평형의 분양가는 4억3300만원 이었다. 10월 현재 최근 시가는 8억9000만원으로 양도차익은 4억5700만원 이다. 양도세만 1억8000만원이 넘지만 전액 감면 된다. 2006년 9월까지는 양도세가 비과세 되고 2006년 9월이 지나서 양도한다 하더라도 그때까지의 양도소득에 대해서는 전액 감면된다. 또 다른 경우인 강남의 B아파트 32평형은 분양가 3억2600만원으로 최근 시세와 비교한 양도차익은 3억2000만원 정도 된다. 입주후 1년이상 단지로 1억2000만원 정도의 양도세가 산정된다. 하지만 산정일 뿐이다. 2007년5월까지 실과세 `0`이다.


2005년 10월 24일 월요일

[펌] oracle column 길이 구하는 방법

 

1. 보통의 varchar

select length( content ) ... ;

2. BLOB type

SELECT Dbms_Lob.getlength(CONTENT_BLOB) as CONTENT_SIZE, ...


3. LONG RAW type

select length(content) 로는 ORA-00932: inconsistent datatypes  에러가 발생한다.
아래의 PL/SQL 을 작성하여 구해야한다.

1. Single Record 에 대한 예

TO 테이블의 Description 컬럼 길이를 구하는 경우

$ vi len_long.sql
declare
  length_var NUMBER;
  cursor TOY_CURSOR is
    select * from TO;
  toy_val TOY_CURSOR%ROWTYPE;
begin
  open TOY_CURSOR;
  fetch TOY_CURSOR into toy_val;
    length_var := LENGTH(toy_val.Description);
    DBMS_OUTPUT.PUT_LINE('Length of Description: '||length_var);
  close TOY_CURSOR;
end;
/

SQL> set serveroutput on
SQL> @len_long
Length of description : 21

PL/SQL procedure successfully completed.

2. Multiple Record 에 대해서는 cursor FOR Loop 를 사용한다.

$ vi len_long.sql
declare
  length_var NUMBER;
  cursor TOY_CURSOR is
    select * from TOY;
  toy_val TOY_CURSOR%ROWTYPE;
begin
  for toy_val in TOY_CURSOR loop
    length_var := LENGTH(toy_val.Description);
    DBMS_OUTPUT.PUT_LINE('ID: '||toy_val.Toy_ID);
    DBMS_OUTPUT.PUT_LINE('Length of Description: '||length_var);
  end loop;
end;
/

SQL> set serveroutput on
SQL> @len_long  
ID: 1
Length of Description: 21
ID: 2
Length of Description: 27

PL/SQL procedure successfully completed.

[펌] Dictionary를 조회할 때 매우 유용한 SQL문

Dictionary를 조회할 때 매우 유용한 SQL문

select * from dict
where lower(comments) like lower('%&dictionary_comments%');
--------------------------------------
select * from dict
where lower(table_name) like lower('%&dictionary_name%');
--------------------------------------
column table_name format a30
column column_name format a30
column comments format a60 word_wrapped
select * from dict_columns
where lower(table_name) like lower('&dictionary_name')
and lower(column_name) like lower('&column_name');
--------------------------------------
select * from dict_columns
where lower(table_name) like lower('&dictionary_name');

View 모음

SELECT TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE, R_CONSTRAINT_NAME, SEARCH_CONDITION
FROM USER_CONSTRAINTS;
-----------------------------------
SELECT TABLE_NAME, CONSTRAINT_NAME, CONSTRAINT_TYPE, STATUS, VALIDATED, DEFERRABLE, DEFERRED
FROM USER_CONSTRAINTS;
-----------------------------------
SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME
FROM USER_CONS_COLUMNS;
-----------------------------------
SELECT A.TABLE_NAME, B.COLUMN_NAME, A.CONSTRAINT_NAME,
A.CONSTRAINT_TYPE, A.R_CONSTRAINT_NAME, A.SEARCH_CONDITION
FROM USER_CONSTRAINTS A, USER_CONS_COLUMNS B
WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME;
-----------------------------------
SELECT T.TABLE_NAME, T.CONSTRAINT_NAME, C.COLUMN_NAME,
T.DEFERRABLE, T.DEFERRED, T.VALIDATED
FROM DBA_CONSTRAINTS T, DBA_CONS_COLUMNS C
WHERE T.CONSTRAINT_NAME = C.CONSTRAINT_NAME
AND T.OWNER LIKE '%&OWNER%'
AND T.TABLE_NAME LIKE '%&TABLE_NAME%';
-----------------------------------
SELECT OBJECT_NAME, OBJECT_TYPE, OBJECT_ID, DATA_OBJECT_ID, CREATED, TIMESTAMP, LAST_DDL_TIME
FROM USER_OBJECTS
ORDER BY OBJECT_TYPE;
----------------------------------
SELECT VIEW_NAME, TEXT
FROM USER_VIEWS;
-----------------------------------
SELECT *
FROM USER_SEQUENCES;
-----------------------------------
SELECT SYNONYM_NAME, TABLE_OWNER, TABLE_NAME
FROM USER_SYNONYMS;
-----------------------------------
SELECT TABLESPACE_NAME, INITIAL_EXTENT, NEXT_EXTENT, MIN_EXTENTS, MAX_EXTENTS,
PCT_INCREASE, MIN_EXTLEN, STATUS, CONTENTS, ALLOCATION_TYPE
FROM DBA_TABLESPACES;
----------------------------------
롤백세그먼트의 일반적인 정보
SELECT SEGMENT_NAME, OWNER, TABLESPACE_NAME,
INITIAL_EXTENT, NEXT_EXTENT, MIN_EXTENTS, STATUS
FROM DBA_ROLLBACK_SEGS;
----------------------------------
현재 인스턴트가 사용하고 있는 롤백세그먼트에 대한 통계 검색
SELECT N.NAME, S.EXTENTS, S.RSSIZE, S.OPTSIZE, S.HWMSIZE, S.XACTS, S.STATUS
FROM V$ROLLNAME N, V$ROLLSTAT S
WHERE N.USN = S.USN;
----------------------------------
롤백세그먼트에 대한 경합
SELECT N.NAME, ROUND(100*S.WAITS/S.GETS)
FROM V$ROLLNAME N, V$ROLLSTAT S
WHERE N.USN = S.USN;
----------------------------------
블록킹 트랜잭션
SELECT S.SID, S.SERIAL#, T.START_TIME, T.XIDUSN, S.USERNAME
FROM V$SESSION S, V$TRANSACTION T, V$ROLLSTAT R
WHERE S.SADDR = T.SES_ADDR
AND T.XIDUSN = R.USN
AND ((R.CUREXT = T.START_UEXT-1)
OR ((R.CUREXT = R.EXTENTS-1) AND T.START_UEXT = 0));
----------------------------------
인덱스에 대한 유효성 확인
SELECT BLOCKS, BTREE_SPACE, USED_SPACE, PCT_USED, LF_ROWS, DEL_LF_ROWS
FROM INDEX_STATS;
----------------------------------
SELECT USERNAME, USER_ID, DEFAULT_TABLESPACE, TEMPORARY_TABLESPACE, PROFILE
FROM DBA_USERS;
----------------------------------
SELECT TABLESPACE_NAME, BYTES, MAX_BYTES, BLOCKS, MAX_BLOCKS
FROM USER_TS_QUOTAS;
-----------------------------------
SELECT TABLESPACE_NAME, FILE_ID, FILE_NAME, BYTES,
AUTOEXTENSIBLE, INCREMENT_BY, MAXBYTES
FROM DBA_DATA_FILES;
-----------------------------------
SELECT FILE#, STATUS, RFILE#, BYTES, BLOCKS, CREATE_BYTES, BLOCK_SIZE, NAME
FROM V$DATAFILE;
-----------------------------------
SELECT FILE#, STATUS
FROM V$BACKUP;
-----------------------------------
SELECT *
FROM DBA_FREE_SPACE
ORDER BY BLOCK_ID;
-----------------------------------
SELECT A.TABLESPACE_NAME, A.BYTES, A.STATUS, B.STATUS, B.ENABLED, B.NAME
FROM DBA_DATA_FILES A, V$DATAFILE B
WHERE A.FILE_ID = B.FILE# AND A.TABLESPACE_NAME LIKE '%&TABLESPACE_NAME%';
-----------------------------------
SELECT TABLESPACE_NAME, EXTENTS_COALESCED, TOTAL_BYTES, BYTES_COALESCED
FROM DBA_FREE_SPACE_COALESCED;
-----------------------------------
SELECT A.TABLESPACE_NAME "TABLESPACE",
B.FILE_NAME "FILE",
B.BYTES "TOTAL SIZE",
C.BYTES "SIZE LEFT"
FROM DBA_TABLESPACES A, DBA_DATA_FILES B, DBA_FREE_SPACE C
WHERE A.TABLESPACE_NAME = B.TABLESPACE_NAME AND
A.TABLESPACE_NAME = C.TABLESPACE_NAME AND
A.TABLESPACE_NAME LIKE '%&TABLESPACE_NAME%';
-----------------------------------
SELECT SEGMENT_NAME, SEGMENT_TYPE, TABLESPACE_NAME, BYTES, BLOCKS, EXTENTS, INITIAL_EXTENT, NEXT_EXTENT
FROM USER_SEGMENTS;
-----------------------------------
SELECT INDEX_NAME, TABLE_NAME, UNIQUENESS, INDEX_TYPE, TABLESPACE_NAME
FROM USER_INDEXES;
-----------------------------------
SELECT LINE, POSITION, TEXT
FROM USER_ERRORS
ORDER BY SEQUENCE;
-----------------------------------
SELECT *
FROM USER_SOURCE;
-----------------------------------
SELECT SEGMENT_NAME, PARTITION_NAME, TABLESPACE_NAME, EXTENT_ID, BYTES, BLOCKS
FROM USER_EXTENTS
ORDER BY SEGMENT_NAME, EXTENT_ID;
-----------------------------------
SELECT TABLESPACE_NAME, SEGMENT_NAME, FILE_ID, EXTENT_ID, BLOCK_ID, BLOCKS
FROM DBA_EXTENTS
ORDER BY EXTENT_ID;
-----------------------------------
SELECT OPERATION, OPTIONS, OBJECT_NAME, ID, PARENT_ID, POSITION
FROM PLAN_TABLE
ORDER BY ID;
-----------------------------------
SELECT NUM_ROWS, BLOCKS, EMPTY_BLOCKS, AVG_SPACE, CHAIN_CNT, AVG_ROW_LEN
FROM USER_TABLES;
-----------------------------------
SELECT COLUMN_NAME, NUM_DISTINCT, LOW_VALUE, HIGH_VALUE, DENSITY
FROM USER_TAB_COLUMNS;
-----------------------------------
SELECT TABLE_NAME, TABLE_TYPE_NAME, PARENT_TABLE_NAME, PARENT_TABLE_COLUMN
FROM USER_NESTED_TABLES;
-----------------------------------
SELECT *
FROM DBA_PROFILES;
-----------------------------------
SELECT *
FROM USER_RESOURCE_LIMITS;
-----------------------------------
SELECT *
FROM USER_PASSWORD_LIMITS;
-----------------------------------
SELECT *
FROM V$OPTION;
-----------------------------------
SELECT *
FROM V$PARAMETER;
-----------------------------------
SELECT DISTINCT OBJECT_TYPE
FROM DBA_OBJECTS;
-----------------------------------
SELECT OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_TYPE, CREATED
FROM DBA_OBJECTS
WHERE OWNER LIKE '%&OWNER%'
AND OBJECT_TYPE LIKE '%&OBJECT_TYPE%'
ORDER BY OBJECT_NAME;
-----------------------------------
SELECT OWNER, TABLE_NAME, TABLESPACE_NAME
FROM DBA_TABLES
WHERE TABLE_NAME LIKE '%&TABLE_NAME%'
ORDER BY OWNER, TABLE_NAME;
-----------------------------------
SELECT VIEW_NAME, TEXT
FROM DBA_VIEWS
WHERE VIEW_NAME LIKE '%&VIEW_NAME%';
-----------------------------------
SELECT *
FROM DBA_SYS_PRIVS
WHERE GRANTEE LIKE '%&ROLE%';
-----------------------------------
SELECT OWNER, SYNONYM_NAME, TABLE_OWNER, TABLE_NAME
FROM DBA_SYNONYMS
ORDER BY 2, 1, 3;
-----------------------------------
<클러스터>

클러스터의 일반적인 정보(블록파라미터..)
SELECT * FROM DBA_CLUSTERS
WHERE OWNER LIKE '%&OWNER%';

클러스터 테이블 및 클러스터 키 조회
SELECT OWNER, CLUSTER_NAME, CLU_COLUMN_NAME, TABLE_NAME
FROM DBA_CLU_COLUMNS
WHERE OWNER LIKE '%&OWNER%';

SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE
FROM DBA_TAB_COLUMNS
WHERE OWNER LIKE '%&OWNER%';
-----------------------------------
IOT 조회
SELECT T.TABLE_NAME AS "IOT", O.TABLE_NAME AS "OVERFLOW",
I.INDEX_NAME AS "INDEX", O.TABLESPACE_NAME AS "OVERFLOW TBS",
I.TABLESPACE_NAME AS "INDEX TBS", I.PCT_THRESHOLD
FROM DBA_TABLES T, DBA_TABLES O, DBA_INDEXES I
WHERE T.OWNER = O.OWNER
AND T.TABLE_NAME = O.IOT_NAME
AND T.OWNER = I.OWNER
AND T.TABLE_NAME = I.TABLE_NAME
AND T.OWNER LIKE '%&OWNER%';
-----------------------------------
SELECT USERNAME, TIMESTAMP, ACTION_NAME
FROM DBA_AUDIT_TRAIL;
-----------------------------------
SELECT USERID, OBJ$NAME, SES$ACTIONS, TIMESTAMP#
FROM SYS.AUD$
WHERE OBJ$NAME LIKE '%&OBJECT_NAME%';
-----------------------------------
SELECT SESSIONID, STATEMENT, TIMESTAMP#, USERID, TERMINAL, ACTION#,
OBJ$CREATOR, OBJ$NAME, SES$ACTIONS, COMMENT$TEXT, SPARE1
FROM SYS.AUD$;

[펌] 중요한 view들

분류

성능뷰 / 딕셔너리

딕셔너리

세션과 관련된 정보

V$SESSION

세션에 대한 전반적인 정보를 보여준다

V$SESSSTAT

세션의 현황에 대한 통계정보를 보여준다

V$SESSION_WAIT

세션의 WAITING 통계정보를 보여준다

V$SESSION_EVENT

세션의 현재 WATING EVENT를 보여준다

V$SESS_IO

세션의 IO현황을 보여준다

V$STATNAME

SESSSTAT STATUS의 이름을 보여준다.

성능 관련 정보

V$SYSTAT

시스템 전반의 성능 통계 정보를 보여준다

V$SYSTEM_EVENT

시스템의 WATING EVENT별 통계정보를 보여준다

V$LIBRARYCACHE

라이브러리 캐쉬 사용 정보를 보여준다.

V$ROWCACHE

데이터 딕셔너리의 사용정보를 보여준다

V$LATCH

LATCH에 대한 정보를 보여준다

V$LOCK

LOCK에 대한 정보를 보여준다

V$LOCKED_OBJECT

LOCK이 걸린 오브젝트에 대한 정보를 보여준다

V$SQLAREA

SQLAREA에 대한 정보를 보여준다

V$WAITSTAT

시스템의 현재 Waiting현황을 보여준다

SQL관련

V$SQL

Parse SQL문장을 보여줌

V$SQLTEXT

라인별로 SQL문장을 보여줌

V$SQLTEXT_WITH_NEWLINES

NewLine을 포함하여 SQL문장을 보여줌

시스템
구성정보

V$SGA

SGA 의 정보를 보여준다

V$PARAMETER

InitSID.ora 등에서 설정된 파라메터, 즉 데이터베이스의 구동되었을 때의 환경 파라메터 정보이다

V$CONTROLFILE

Control 파일에 대한 정보를 보여준다.

V$DATAFILE

데이터 파일에 대한 정보를 보여준다.

V$LOG, V$LOGFILE

리두 로그에 대한 정보를 보여준다.

USER

DBA_USERS

데이터베이스 USER에 대한 정보를 보여준다

권한

DBA_ROLES

ROLE에 대한 정보를 보여준다.

DBA_TAB_PRIVS

테이블에 대한 권한이 설정된 정보를 보여 준다

DBA_SYS_PRIVS

SYSTEM 권한이 설정된 정보를 보여준다

DBA_ROLE_PRIVS

ROLE에 대한 권한이 설정된 정보를 보여 준다.

DBA_COL_PRIVS

컬럼 단위로 권한이 설정된 정보를 보여준다.

세그먼트&오브젝트

DBA_SEGMENTS

세그먼트(저장공간이 있는 오브젝트)에 대한 정보를 보여준다.

DBA_OBJECTS

모든 오브젝트에 대한 정보를 보여준다.

테이블

스페이스

V$TABLESPACE

테이블 스페이스에 대한 정보를 보여준다.

DBA_TABLESPACES

테이블 스페이스에 대한 정보를 보여준다.

DBA_DATA_FILES

테이블스페이스를 구성하고 있는 데이터 파일에 대한 정보를 보여준다.

DBA_FREE_SPACE

아직 사용되지 않은 영역에 대한 정보를 보여준다.

DBA_EXTENTS

할당된  EXTENT의 정보를 보여준다.

DBA_TS_QUOTAS

QUOTA가 설정된 정보를 보여준다

테이블

DBA_TABLES

테이블에 대한 정보를 보여준다.

DBA_TAB_COLUMNS

테이블을 구성하는 컬럼에 대한 정보를 보여준다

DBA_TAB_COMMENTS

테이블의 설명에 대한 정보를 보여준다

DBA_PART_TABLES

파티션 테이블에 대한 정보를 보여준다.

DBA_PART_KEY_COLUMNS

파티션을 구성하는 기준 컬럼에 대한 정보를 보여준다

DBA_COL_COMMENTS

컬럼에 대한 설명에 대한 정보를 보여 준다

인덱스

DBA_INDEXES

인덱스에 대한 정보를 보여준다.

DBA_PART_INDEXES

파티션된 인덱스에 대한 정보를 보여준다

DBA_IND_COLUMNS

인덱스를 구성하는 컬럼에 대한 정보를 보여준다

CONSTRAINT

DBA_CONSTRAINTS

테이블에 걸려있는 제약조건을 보여준다.

DBA_CONS_COLUMNS

제약조건을 구성하는 컬럼에 대한 조건을 보여준다.

DBA_VIEWS

VIEW를 정의한 정보를 보여준다.

시노님

DBA_SYNONYMS

시노님에 대한 정보를 보여준다.

시퀀스

DBA_SEQUENCES

시퀀스에 대한 정보를 보여준다.

DB LINK

DBA_DB_LINKS

DB 링크에 대한 정의를 보여준다

트리거

DBA_TRIGGERS

트리거에 대한 정의를 보여준다.

DBA_TRIGGER_COLS

컬럼 단위로 작성된 트리거에 대한 정의를 보여준다.

ROLLBACK

DBA_ROLLBACK_SEGS

롤백세그먼트에 대한 정보를 보여 준다.

FUNCTION, PROCEDURE,

PACKAGE

DBA_SOURCE

FUNCTION, PROCEDURE,PACKAGE를 구성하는 PL/SQL 소스코드를 보여준다

[펌] default 값 확인

SELECT *                   -- data_default 컬럼
FROM dba_TAB_COLUMNS
where table_name= '테이블 명'

 

 

아 난 정말 바보인가보다..ㅠ.ㅠ

 

 

참고로 default  값을 삭제하고 싶으면

Alter Table 테이블 Modify(column  column type   default null);

2005년 10월 21일 금요일

[펌] 블루마인드 X-Internet 기반 우리은행연수관리시스템 개발

X-Internet / RIA 전문 개발 업체인 블루마인드 커뮤니케이션 (http://bluemind.co.kr)에서 우리은행 사내 인사연수 시스템을 X- Internet / RIA기반으로 개발했다고 밝혔다.

전세계 98%이상 컴퓨터에 탑재되어 있는 플래시를 기반으로 구동되기 에다양한 OS와 디바이스에서 구동이 가능하고 기존 HTML의 사용 불편 함과 C/S의 유지보수와 운영 환경의 제한 단점등을 해결해 사용자에게 편리한 인터페이스 환경과 빠른 구동 속도를 제공해 주고 있다.

자체 UI 프레임워크하에 개발된 우리은행 사내 인사연수 시스템에 들어간 플래시 어플리케이션 모듈은 컨테이너가 230여개가 될 정도로 복잡한 규모이며 "현재 국내외의 플래시기반 어플리케이션 규모중 가장 큰 사례" 가 될 것이라고 밝혔다.
간단한 예를 들면 블루마인드에서 개발한 극장 예약에 적용하는 RIA 의 경우(www.cinus.co.kr)구성 컨테이너가 보통 6개정도이고 복잡할 경우 10개정도로 컨테이너가 구성된다.

이와 같은 시스템의 성공적인 개발 적용을 통해 기존에 극장 예약 등에 적용되는 형태에서 다양한 기업의 비즈니스 업무에서 성공적인 확대 적용이 가능할 것이다.


또한 연수 담당자들과 시스템 운영 설명회를 가지면서 담당자들의 의견을 들어본 결과 시스템 운영 담당자의 경우 실제 4배에서 느낌상으로는 40배정도 어플리케이션 속도가 개선이 되었다고 이야기를 하고 있으며 실질적으로 이것을 사용해본 우리은행 직원들 대부분도 인터페이스의 개선 효과도 있지만 그보다는 이전에 만든 HTML 기반 어플리케이션에 비해 속도가 놀랄만큼 빨라졌다고 인정하고 있었다.
업무 개선효과 면에서도 예전에 1시간 넘게 걸리던 작업이 10분도 채 걸리지 않게 되어서 좀더 효율적인 작업 환경이 이루어졌다고 밝혔다.


블루마인드 커뮤니케이션의 CEO인 김태식 대표는 "우리은행 사내 인사 연수 시스템을 통해 플래시 기반 X-Internet 어플리케이션의 우수성이 입증되었기에 다양한 비즈니스에 적용 확대가 될 것으로 기대한다"고 말했다. 우리은행 사내 인사연수 시스템의 데모는

http://www.bluemind.co.kr/woori 에서 볼 수 있다.

출처 : http://itwarehouse.co.kr/

2005년 10월 17일 월요일

XML 대소문자 변환하기

 

XSLT Case Conversion Solution 

The following article was written by Erich Von Hauske N. after a discussion on XSLTalk.  Corey Haines started a tread on how to do recursion in XSLT, which lead to this solution that Erich and Corey came up with. 

Download the source

The solution of a problem like case conversion can take many forms, especially when you use a language like XSLT, which gives you the flexibility to give many solutions; each one with a different degree of recursiveness. The solution presented in this document is a middle-ground solution, it's recursive, but not as recursive as it could get, nevertheless it has a better performance than the completely recursive solution.

What we are demonstrating is firstly how to convert your XML data from on case to another.  As XML is case sensitive, when you need to do searches on your data, using the translate function demonstrated enables case-insensitive searches.  Then we are demonstrating a solution for implementing proper case converting - which demonstrates the recursion.

Upper Case Transformation

Upper and lower case transformations are very easy in XSLT thanks to the translate function. An alternative solution could be to implement the transformation and switch character by character, but since XSLT already gives us a better solution, let's better take advantage of it.  Please find the full source in the downloadable file.

Firstly lets place all the letters of the alphabet, lower case and upper case in variables.

<xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
<xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
To then convert our data to upper case we use the translate method, which replaces all the lower case characters with upper case.
<xsl:value-of select="translate($toconvert,$lcletters,$ucletters)"/>

Lower Case Transformation

The lower case transformation is basically the same:

<xsl:value-of select="translate($toconvert,$ucletters,$lcletters)"/>

Proper Case Transformation

The interesting part of this exercise is really in here: the proper case transformation. The presented solution first translates the entire string to lower case, and after that it translate only the first letter of every word to upper case. Here's the code:

<xsl:template name='convertpropercase'>
<xsl:param name='toconvert' />

<xsl:if test="string-length($toconvert) > 0">
	<xsl:variable name='f' select='substring($toconvert, 1, 1)' />
	<xsl:variable name='s' select='substring($toconvert, 2)' />
	
	<xsl:call-template name='convertcase'>
		<xsl:with-param name='toconvert' select='$f' />
		<xsl:with-param name='conversion'>upper</xsl:with-param>
	</xsl:call-template>

<xsl:choose>
	<xsl:when test="contains($s,' ')">
		<xsl:value-of select='substring-before($s," ")'/>
		<xsl:text> </xsl:text>
		<xsl:call-template name='convertpropercase'>
		<xsl:with-param name='toconvert' select='substring-after($s," ")' />
		</xsl:call-template>
	</xsl:when>
	<xsl:otherwise>
		<xsl:value-of select='$s'/>
	</xsl:otherwise>
</xsl:choose>bv
</xsl:if>
</xsl:template>

Basically what it does is to check if the string to covert has characters (end condition for recursion), and if it has characters then it breaks the string in two parts: the first letter and the rest of the string, converts the first letter to upper case and checks if the rest of the string contains spaces (word separators), if it contains spaces then it outputs the rest of the current word (substring-before($s," ")) and calls the convertpropercase template with the rest of the string ('substring-after($s," ")') to convert the rest of the words to proper case.

Procedural Programming in XSLT 

If you were wondering what the xsl:call-template element does, it allows one to use functions in XSLT, where basically you can call a template from anywhere in the XSLT.  You pass the template parameters, like you do in functions.  Instead of the template having a matching element, you give it a name. (<xsl:template name='convertpropercase'>)

Declaring the template:

  <xsl:template name='convertcase'>
    <xsl:param name='toconvert' />
    <xsl:param name='conversion' />
   ....
  </xsl:template>

Calling the template:

	<xsl:call-template name='convertcase'>
		<xsl:with-param name='toconvert' select='$f' />
		<xsl:with-param name='conversion'>upper</xsl:with-param>
	</xsl:call-template>
View the Source

 

2005년 10월 13일 목요일

[펌] XML을 PDF문서로 만들기

 

XML을 PDF문서로 만들기

Summary :
XML을 처음 접할 때 XML의 장점으로 많이 듣는 것중의 하나는 XML로 작성된 문서를 다양한 문서로 변환하기 쉽다는 것이다. XML로 작성된 문서는 적용하는 XSL에 따라 XML, HTML, WML, PDF등 다양한 형태의 문서로 변환할 수 있다. 하지만 국내 현실에서 XML공부할 때 HTML로만의 변환에만 치우치는 경향이 있어 XML을 PDF로 변환하는 방법에 대하여 알아본다. XML을 PDF로 변환할 때 해결하기 힘든 부분이 한글이 깨지는 문제이다. 따라서 한글문제에 대한 해결책도 제시한다.

  PDF문서 변환을 위한 사전 준비작업

XML을 처음 접할 때 XML의 장점으로 많이 듣는 것중의 하나는 XML로 작성된 문서를 다양한 문서로 변환하기 쉽다는 것이다. XML로 작성된 문서는 적용하는 XSL에 따라 XML, HTML, WML, PDF등 다양한 형태의 문서로 변환할 수 있다.
하지만 국내 현실에서 XML공부할 때 HTML로만의 변환에만 치우치는 경향이 있다. 따라서 XML문서를 PDF문서로 변환하는 방법에 대하여 살펴봄으로서 XML의 장점에 대하여 실감할 수 있을 것이다. PDF문서로 변환하기 위해 Apache Group에서 개발을 진행하고 있는 FOP를 이용하도록 하겠다.
많은 개발자들이 FOP를 이용하여 XML문서를 PDF만들려고 시도하고, 성공한 경우도 많이 보아왔다. 하지만 최종적으로 문제가 되는 것은 역시나 한글 문제였다. 자바지기를 운영하면서 PDF변환시 한글문제를 해결하지 못해 고민하는 개발자들을 많이 보아왔다. 필자역시 국내 웹을 돌아다니면서 한글문제를 해결하려고 노력했으나 해결책을 제시하는 곳이 거의 전무한 상태였다. 역시나 이런 경우에는 삽질(?)이 최고인듯하다. 삽질의 결과 한글문제를 해결할 수 있었고, 이번 강좌를 통하여 해결책을 제시하고자 한다.

FOP설치단계
1. http://xml.apache.org/fop/download.html에서 최신 FOP를 다운 받는다. FOP에 대하여 익숙하지 않은 개발자들은 http://xml.apache.org/fop/index.html에서 FOP에 대한 정보를 얻을 수 있다.
FOP(Formatting Objects Processor)에 대하여 간단하게 설명한다면 XML문서를 다양한 문서로 변환하기 Apache Group에서 개발하고 있는 세계 최초의 출력 Fomatter라고 FOP는 소개한다. 첫번째의 문서 변환이 PDF로 촛점이 맞추어져 있다.
2. 다운받은 ZIP파일을 개발자들이 원하는 적당한 곳에 압축을 푼다.(예: D:\XML\fop-0.20.4)
3. fop-0.20.4\build의 fop.jar와 fop-0.20.4\lib 아래에 5개의 jar파일(avalon-framework-cvs-20020315.jar, batik.jar, xalan-2.3.1.jar, xercesImpl-2.0.1.jar, xml-apis.jar)이 있을 것이다.
Prompt상에서 컴파일 및 테스트를 하고자 한다면 위 6개 파일을 클래스 패스에 추가한다. 이번 강좌는 Apache-Tomcat을 이용하여 애플리케이션내에서 테스트를 해볼 생각이다. Tomcat을 이용할 경우에는 "애플리케이션 이름\WEB-INF\lib"내에 사용하고자하는 jar파일을 추가할 경우 애플리케이션이 시작될 때 자동으로 로딩된다.
4. http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.0.6/bin/에서 Tomcat 4.0.6을 다운 받는다. 다른 버전의 Tomcat을 다운받아도 된다. Tomcat에 대한 설치방법은 대부분의 개발자들이 알고 있을 것으로 생각되어 이 강좌에서는 생략한다.
5. Tomcat설치디렉토리\webapps\Application Name\WEB-INF\lib아래에 위 3에서 설명한 6개의 jar파일을 복사한다.
(예: D:\Server\Tomcat-4.0.6\webapps\xmlfop\WEB-INF\lib)

이상으로 FOP를 이용하여 XML문서를 PDF로 변환하기 위한 준비작업이 완료되었다. 이 강좌에서 진행하는 모든 소스는 테스트의 편의성을 위하여 JSP로 모두 작성할 생각이다. Servlet 및 클래스내에서 좀 더 유연하게 관리하는 방법은 계속되는 강좌에서 다룰 생각이다.

  FOP문서를 PDF로 변환하기

이번 강좌에서 진행할 모든 예제는 위에서 다운받은 FOP에 예제로 들어있는 파일들을 기준으로 설명하도록 하겠다. FOP문서의 작성 방법이나 PDF의 스키마에 대한 설명은 다른 문서를 참조하기 바란다. 이번 강좌는 작성되어 있는 FOP문서를 PDF로 변환하는 방법에 대하여만 살펴보도록 할 예정이다.

예제 파일들은 "fop-0.20.4\docs\examples"에 보면 다양한 예제들이 들어 있다. 이번 강좌에서는 "fop-0.20.4\docs\examples\fo"와 "fop-0.20.4\docs\examples\markers"에 있는 예제들을 이용하여 PDF문서로 변환해 보도록 하겠다. 이 강좌에서 사용되는 모든 소스는 첨부되는 파일로 제공될 것이다.

이번절에서는 FOP로 작성되어 있는 문서를 PDF로 변환하는 방법에 대하여 먼저 살펴보도록 하겠다. PDF문서를 작성하는 것이 어려워보이지만 작성되는 소스를 보면 상당히 간단하다고 느낄 수 있을 것이다.

<?xml version="1.0" encoding="utf-8"?>

<fo:root font-family="Times Roman" font-size="12pt" text-align="center" xmlns:fo="http://www.w3.org/1999/XSL/Format">

<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
	margin-top="75pt" margin-bottom="25pt" margin-left="100pt" margin-right="50pt">
	<fo:region-body margin-bottom="50pt"
              background-image="file:../../graphics/xml_feather_transparent.gif"/>
	<fo:region-after extent="25pt"/>
</fo:simple-page-master>

</fo:layout-master-set>

<fo:page-sequence master-reference="simple">

<fo:static-content flow-name="xsl-region-after">
	<fo:block text-align-last="center" font-size="10pt">
		<fo:page-number/>
	</fo:block>
</fo:static-content>

<fo:flow flow-name="xsl-region-body">
<fo:block font-size="18pt" font-weight="bold" background-color="#dddddd">
Simple example for background-image</fo:block>
<fo:block font-size="14pt" space-before="1.6cm"
      text-align="end" white-space-collapse="false"
      background-repeat="no-repeat"
      background-image="file:../../graphics/linux.bmp">
background-image in a block
1 &#13;
2 &#13;
3 &#13;
4 &#13;
5 &#13;
</fo:block>
</fo:flow>

</fo:page-sequence>

</fo:root>

bgimage.fo  : PDF문서로 변환할 FO파일

FO문서는 XML형태로 작성된다. 위 FO문서를 이해하기 힘들것이다. 이해하지 못해도 PDF문서를 만드는데는 크게 상관없다. 하지만 예제만으로의 PDF문서 생성이 아닌 개발자들이 원하는 PDF문서를 만들기 위해서는 FO태그들에 대하여 공부해야 할 것이다.
HTML문서도 원하는 스타일을 만들기 위하여 정해진 태그를 사용하듯이 FO문서도 원하는 PDF문서를 만들기 위하여 정해진 태그를 사용하게 되는 것이다.

<%@ page language="java" contentType="text/html;charset=euc-kr" %>

<%@ page import="java.io.FileOutputStream"%>
<%@ page import="org.xml.sax.InputSource"%>
<%@ page import="org.apache.fop.apps.Driver"%>

<%
String path = "D:\\Server\\Tomcat-4.0.6\\webapps\\xmlfop\\fo\\";

String outputPath = path + "bgimage.pdf";
String inputPath = path + "bgimage.fo";
FileOutputStream fops = new FileOutputStream(outputPath);

Driver driver=new Driver( new InputSource(inputPath),
                          fops);
driver.setRenderer(Driver.RENDER_PDF);

driver.run();

fops.close();

out.println("PDF Create Success!!");
%>

fopToPDF.jsp  : bgimage.fo문서를 bgimage.pdf로 변환하는 소스

위에서 본 bgimage.fo파일을 bgimage.pdf로 변환하는 소스파일이다. FO문서를 만드는 것이 어려운 작업이다. 하지만, 만들어진 FO문서를 PDF로 생성하는 것은 생각보다 간단하다.
http://localhost:8080/xmlfop/fopToPDF.jsp를 실행하여 PDF파일을 생성한다.
PDF문서를 만들기 위해서는 먼저 Driver를 생성한다. API를 참조하면 다양한 생성자가 있지만, Driver객체 생성시 입력 FO와 생성될 출력스트림을 위와 같이 정의할 수 있다. Driver의 setRenderer()를 이용하여 출력할 문서의 형태를 결정할 수 있다. 위는 "Driver.RENDER_PDF"를 전달하여 PDF문서임을 알 수 있다.
최종적으로 Driver의 run()메써드를 이용하여 FO파일을 PDF문서로 변환이 가능하다. 어려워 보이는 작업이였지만 쉽게 PDF문서를 생성할 수 있다. 위 소스에서 path를 개발자들의 path에 맞도록 수정만 해주면 테스트해볼 수 있다. fo 디렉토리 아래에 있는 다른 FO파일들을 이용하여 PDF문서를 생성해 보기바란다.
위 소스의 실행결과 생성된 PDF문서는 다음과 같다.

bgimage.pdf문서  : fopToPDF.jsp에 의하여 생성된 bgimage.pdf문서

  XML과 XSL을 이용하여 PDF문서 만들기

지금까지는 FOP문서를 PDF문서로 생성하는 방법에 대하여 살펴보았다. 그렇다면 XML문서를 XSL을 이용하여 PDF문서로 만드는 방법은 어떻게 될까? XML에 약간 친숙한 독자라면 이미 알고 있는 개발자들도 있을 것으로 생각된다. 우리가 XML문서를 HTML문서로 만들때를 생각해보자. XML태그에 HTML태그들이 없어도 XSL을 이용하면 HTML문서로의 변환이 가능하다. PDF문서를 작성할 때도 같다. XML문서에 XSL을 이용하여 FOP문서로 만들어 준 후 앞에서 살펴본 방식으로 PDF문서를 만들 수 있도록 하면 된다.
XML과 XSL에 익숙한 개발자라면 FOP문서를 만드는 것은 어렵지 않을 것이다. HTML문서를 만들기 위해 HTML 태그를 알아야 하듯이 PDF문서를 만들기 위해서는 FOP태그를 알아야 한다. FOP태그의 사용법에 대해서는 FOP사이트나 FOP관련문서를 참조하기 바란다.
앞으로 보게될 예제는 FOP에서 제공하는 예제를 이용하여 PDF문서를 작성해 보도록 하겠다.

<?xml version="1.0"?>
<glossary>
<term-entry>
	<term>basic-link</term>
	<definition>The fo:basic-link is used for representing the start resource
	of a simple link.</definition>
</term-entry>
<term-entry>
	<term>bidi-override</term>
	<definition>The fo:bidi-override inline formatting object is used where
	it is necessary to override the default Unicode-bidirectionality
	algorithm direction for different (or nested) inline scripts in
	mixed-language documents.</definition>
</term-entry>

..중간생략..
<term-entry>
	<term>wrapper </term>
	<definition>The fo:wrapper formatting object is used to specify inherited
	properties for a group of formatting objects. It has no additional
	formatting semantics.</definition>
</term-entry>
</glossary>

glossary.xml  : FOP에서 제공하는 예제 XML소스.
전체 소스 보기

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:fo="http://www.w3.org/1999/XSL/Format"
	version="1.0">
	
<xsl:template match="glossary">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">

	<fo:layout-master-set>

    <fo:simple-page-master master-name="all"
		page-height="11.5in" page-width="8.5in"
        margin-top="1in" margin-bottom="1in" 
        margin-left="0.75in" margin-right="0.75in">
		<fo:region-body margin-top="1in" margin-bottom="0.75in"/>
		<fo:region-before extent="0.75in"/>
		<fo:region-after extent="0.5in"/>
	</fo:simple-page-master>

	</fo:layout-master-set>
	..중간 생략..
<xsl:template match="definition">
	<fo:block text-align="start" start-indent="2em">
		<xsl:value-of select="."/>
	</fo:block>
</xsl:template>

</xsl:stylesheet>

glossary.xsl  : FOP에서 제공하는 예제 XSL소스.
전체 소스 보기

PDF로 만들 XML과 XSL에 대하여 살펴보았다. 전체소스를 보고 싶다면 각 소스아래의 전체소스보기를 클릭하여 전체소스를 보기 바란다. 여기서는 각 소스의 일부분만을 제공했다.
XML문서는 이전까지 우리가 작성했던 XML문서와 같은 형태이다. 다른 부분은 XSL이다. 이전까지 XML을 HTML로 만들었던 개발자들이라면 XSL에서 HTML태그들을 사용했을 것이다. 그러나 위 예제의 glossary.xsl에서는 FO태그를 이용하여 스타일을 결정하고 있다.

<%@ page language="java" contentType="text/html;charset=euc-kr" %>

<%@ page import="java.io.*"%>
<%@ page import="javax.xml.transform.*"%>
<%@ page import="javax.xml.transform.sax.*"%>
<%@ page import="javax.xml.transform.stream.*"%>
<%@ page import="org.apache.fop.apps.*"%>

<%
String path = "D:\\Server\\Tomcat-4.0.6\\webapps\\xmlfop\\markers\\";

String outputPath = path + "glossary.pdf";
String xml = path + "glossary.xml";
String xsl = path + "glossary.xsl";

FileOutputStream fops = new FileOutputStream(outputPath);

Driver driver =new Driver();
driver.setOutputStream(fops);
driver.setRenderer(Driver.RENDER_PDF);

Transformer transformer=TransformerFactory.newInstance()
		.newTransformer(new StreamSource(new File(xsl)));

transformer.transform(new StreamSource(new File(xml)), 
	new SAXResult(driver.getContentHandler()));

fops.close();

out.println("PDF Create Success!!");
%>

xmlToPDF.jsp  : XML과 XSL을 이용하여 PDF문서를 생성하는 소스

http://localhost:8080/xmlfop/xmlToPDF.jsp를 실행하여 PDF파일을 생성한다. PDF파일이 정상적으로 생성될 것이다.
Driver를 이용하여 PDF를 생성하는 과정은 앞에서 FOP문서를 PDF문서로 생성할 때와 비슷하다. XML문서의 변환에서 한가지 추가된 것으로 XSL을 적용하여 FOP문서로 변환하는 과정이다. XSLT Processor는 Xalan이 이용되었다. Xalan XSLT Processor를 이용하여 XML문서를 HTML로 변환해본 개발자들이라면 위 예제를 쉽게 이해할 수 있을 것이다.
위 소스 실행결과 생성된 PDF문서는 다음과 같다.

glossary.pdf문서  : xmlToPDF.jsp에 의하여 생성된 glossary.pdf문서

  한글로 작성된 PDF문서만들기

지금까지 FO파일과 XML파일을 이용하여 PDF문서를 작성하는 방법에 대하여 살펴보았다. XML파일을 이용하여 PDF를 작성했던 예제에서 glossary.xml에 한글을 추가해보자. 한글을 추가한 다음 XML과 XSL문서 모두를 <?xml version="1.0" encoding="euc-kr"?gt;으로 수정한 다음 PDF문서로 재작성해보자. 한글이 깨져서 ??와 같이 깨져서 보일 것이다. HTML문서에서는 이와 같이 XML, XSL문서의 인코딩만을 바꿔서 한글 문제를 해결할 수 있었다. 그러나 PDF문서의 작성에서는 인코딩만으로는 해결할 수 없다.
위의 glossary.xsl에서 font-family="serif" 부분이 있듯이 PDF문서를 작성할 때는 한글 폰트를 지정해 주어야만 한글을 깨지지 않고 볼 수 있다.
따라서 한글 폰트를 만들어 한글로 작성된 PDF문서를 작성하는 방법에 대하여 살펴본다.
http://xml.apache.org/fop/fonts.html에서 폰트를 추가하는 방법에 대하여 다루고 있다. 이 문서를 기초로 한글 폰트를 추가하는 방법에 대하여 알아보도록 하겠다.

새로운 폰트를 추가하는 과정
1. http://korea.gnu.org/people/chsong/jikji/fonts/에 접속하여 nGulim.ttf를 다운받는다.
2. 다운받은 nGulim.ttf를 "C:\WINNT\Fonts"(Windows 2000의 경우)에 복사한다.
3. FOP의 압축을 푼 디렉토리로 이동하여 "java -cp build\fop.jar;lib\xercesImpl-2.0.1.jar;lib\xml-apis.jar;lib\xalan-2.3.1.jar;lib\batik.jar org.apache.fop.fonts.apps.TTFReader C:\WINNT\Fonts\nGulim.ttf nGulim.xml"의 내용을 담고 있는 Batch파일을 만든다.
만약 Batch파일에 익숙하지 않은 개발자라면 첨부되는 파일에서 AddFont.bat(xmlfop아래에 있다.)을 찾아 FOP설치디렉토리로 복사한다.
4. 생성한 Batch파일을 실행하면 ngulim.xml파일이 생성된다. 생성된 ngulim.xml파일을 "애플리케이션\font\"에 복사한다.
5. 폰트를 추가하기 위해서는"fop-0.20.4\conf"에 있는 userconfig.xml을 수정해야 한다. userconfig.xml을 "애플리케이션\conf\"로 복사한 다음 ngulim.xml을 추가해 주어야 한다.
userconfig.xml을 열어 다음 부분을 추가한다.

<font metrics-file="D:\Server\Tomcat-4.0.6\webapps\xmlfop\font\ngulim.xml" embed-file="C:\WINNT\Fonts\nGulim.ttf" kerning="yes"%gt;
<font-triplet name="ngulim" style="normal" weight="normal"/%gt;
<font-triplet name="ngulim" style="normal" weight="bold"/%gt;
</font>

metrics-file과 embed-file에는 ngulim.xml과 nGulim.ttf의 절대경로를 준다.

이상으로 새굴림폰트를 추가하기 위한 모든 준비가 완료되었다. 만약 위의 과정이 복잡하다고 생각하는 독자들이 있다면 첨부되는 파일에서 conf/userconfig.xml을 열어 자신의 컴퓨터 경로에 맞도록 수정해주면 쉽게 새로운 폰트를 추가할 수 있다.

다음은 새로운 폰트를 사용하는 소스에 대하여 살펴보자.

<%@ page language="java" contentType="text/html;charset=euc-kr" %>

<%@ page import="java.io.*"%>
<%@ page import="javax.xml.transform.*"%>
<%@ page import="javax.xml.transform.sax.*"%>
<%@ page import="javax.xml.transform.stream.*"%>
<%@ page import="org.apache.fop.apps.*"%>

<%
String path = "D:\\Server\\Tomcat-4.0.6\\webapps\\xmlfop\\";

String outputPath = path + "hangulmarkers\\hangulglossary.pdf";
String xml = path + "hangulmarkers\\glossary.xml";
String xsl = path + "hangulmarkers\\glossary.xsl";
String userConfig = path + "conf\\userconfig.xml";

FileOutputStream fops = new FileOutputStream(outputPath);

Options options = new Options(new File(userConfig));

Driver driver =new Driver();
driver.setOutputStream(fops);
driver.setRenderer(Driver.RENDER_PDF);

Transformer transformer=TransformerFactory.newInstance()
		.newTransformer(new StreamSource(new File(xsl)));

transformer.transform(new StreamSource(new File(xml)), 
	new SAXResult(driver.getContentHandler()));

fops.close();

out.println("PDF Create Success!!");
%>

hangulXMLToPDF.jsp  : 새로 추가한 한글 폰트를 사용하는 소스

XML과 XSL은 앞에서 사용한 glossary.xml과 glossary.xsl을 재사용하도록 하겠다. 이 두 파일을 수정해야하기 때문에 수정된 XML, XSL소스는 hangulmarkers디렉토리에서 제공한다.
새로 추가된 한글 폰트를 사용하는 방법은 Options options = new Options(new File(userConfig));부분만 추가하면 된다.
XML과 XSL의 인코딩을 euc-kr로 수정한 다음 XSL에서 ngulim폰트를 사용할 수 있도록 font-family="ngulim"와 같이 font-family항목을 모두 바꾸어 준다.
이제 한글 PDF를 작성하기 위한 모든 준비작업이 끝났다. http://localhost:8080/xmlfop/hangulXMLToPDF.jsp를 실행하여 PDF문서가 정상적으로 만들어 지는지 확인해보자.
아마도 NullpointerException이 발생할 것이다. NullpointerException가 발생하는 원인을 찾아보면 "Failed to read font metrics file D:\Server\Tomcat-4.0.6\webapps\xmlfop\f
ont\ngulim.xml : An invalid XML character (Unicode: 0x0) was found in the elemen
t content of the document."에서 찾을 수 있다. ngulim.xml에 인코딩에 맞지않는 문자가 들어가 있다는 것이다. 필자가 삽질을 시작한 것은 여기서 부터이다. 도저히 이유를 찾지못했다. ngulim.xml의 인코딩을 바꿔보기도 했지만 원인을 찾기가 쉽지 않았다.

역시나 원인은 ngulim.xml에 있었다. ngulim.xml을 열어 처음의 <font-name>NGulim</font-name>처럼 바꾸어 준다. font-name에 들어있는 문자가 인코딩에 맞지 않는 것이였다. 몇일의 삽질끝에 발견했다. 그 때의 기쁨이란 프로그램을 하는 개발자들이라면 모두 느꼈을 것이다.
http://localhost:8080/xmlfop/hangulXMLToPDF.jsp를 실행하여 PDF를 생성해본다. glossary.xml에 한글을 추가하여 한글이 정상적으로 PDF로 생성되는지를 확인해 본다. 위 과정이 맞았다면 정상정으로 생성될 것이다.

한글로 생성된 PDF파일은 다음과 같다.

hangulglossary.pdf문서  : hangulXMLToPDF.jsp에 의하여 생성된 hangulglossary.pdf문서

  결론

지금까지 FOP, XML을 이용하여 PDF문서를 작성하는 방법에 대하여 살펴보았다. PDF를 작성할 때 가장 큰 걸림돌이였던 한글문제에 대해서도 새로운 폰트를 추가하여 해결할 수 있었다. 위에서 사용한 모든 소스는 fopxml.war로 제공될 것이다. 이 파일을 tomcat\webapps\에 넣으면 지금까지의 테스트를 손쉽게 해볼 수 있을 것이다. 수정할 부분은 JSP파일에서 fo와 xml파일들을 경로를 수정해 주기만 하면 된다.
앞으로 FOP강좌에서는 클래스 내에서 위 작업을 손쉽게 할 수 있도록 수정해볼 것이다. 또한 PDF에서 SVG파일을 사용하는 방법에 대하여도 살펴볼 것이다. 만약 여유가 된다면 FOP에서 사용하는 태그에 대하여도 살펴볼 생각이다.

앞으로도 많은 개발자들의 관심이 있기를 바란다. 모든 질문은 XML Q&A란을 이용해주기 바란다. 많은 개발자들과의 정보공유를 위하여 꼭 게시판을 이용해 주기바란다. E-mail을 통한 질문은 삼가해 주기를 바란다.

참고 자료  :