반응형

Simple이란?

Simple은 XML의 직렬화 및 역직렬화 프로세스를 단순화하는 데 사용되는 Java 프레임워크이다. 이름에서 알 수 있듯이 Simple을 사용하는 개발자는 POJO(plain old Java object)를 XML 문서로 변환하는 직렬화 프로세스를 단순화할 수 있다. Simple은 그 반대의 기능도 제공한다. 즉, XML 문서를 POJO로 변환할 수 있으며 이 프로세스를 역직렬화라고 한다.

Simple은 그 이름에 걸맞게 어노테이션을 사용하여 직렬화 또는 역직렬화 프로세스를 수행한다. POJO는 해당 XML 문서의 표시 방법에 따라 어노테이트된다. 일부 필드는 속성으로 어노테이트되고 다른 필드는 요소로 어노테이트된다. 클래스는 일반적으로 루트 요소로 어노테이트된다. 직렬화 프로세스 동안 어노테이션을 해석하고 해당 XML 문서를 생성하는 지루한 프로세스는 프레임워크에 의해 자동으로 처리된다. 또한 어노테이션은 XML 문서가 POJO로 변환되는 역직렬화 프로세스 동안에도 해석된다.

Simple을 사용하면 여러 가지 장점을 얻을 수 있다. 첫 번째 장점은 애플리케이션을 빠르게 개발할 수 있다는 것이다. Simple은 매우 단순하므로 과도한 학습 곡선 또는 개발 오버헤드 없이도 XML 직렬화 및 역직렬화를 사용하는 강력한 애플리케이션을 빠르게 구현할 수 있다.

Simple의 다음 장점은 구성이 필요하지 않다는 것이다. 앞에서 언급한 대로 Simple은 어노테이션을 사용한다. 이러한 어노테이션은 일반적으로 이러한 특성을 가진 프레임워크에 사용되는 XML 기반 구성 파일 대신 사용된다.

마지막으로 Simple을 사용하는 애플리케이션의 풋프린트에 최소한의 공간만 추가된다는 장점이 있다. 즉, 239KB에 불과한 JAR(Java Archive) 파일만 추가된다. 또한 Simple은 다른 프레임워크와 마찬가지로 다른 JAR 파일을 사용하지 않는다.

Simple 다운로드하기

Simple을 사용하려면 먼저 참고자료에 나열되어 있는 Simple 웹 사이트로 이동하여 아카이브를 다운로드해야 한다. 하지만 이 프로세스와 관련하여 좋은 소식과 나쁜 소식이 있다. 좋은 소식은 아카이브라 무료라는 것이고 나쁜 소식은 아카이브가 .tar.gz 형식이라는 것이다. 따라서 Microsoft® Windows® 기본 아카이브 추출기로는 이 아카이브를 열 수가 없기 때문에 WinZip 또는 유사한 아카이브 유틸리티가 필요하다.

파일을 추출한 후 jar 디렉토리를 보면 하나의 JAR 파일(simple-xml-2.1.4.jar)이 있다. 이 파일은 컴파일 시간 및 런타임에 클래스 경로에 있어야 하는 JAR 파일이다.

직렬화하기

오브젝트를 XML 문서로 직렬화하는 작업은 매우 간단하다. 다음 두 단계만 수행하면 된다.

  1. 적절한 어노테이션을 사용하여 POJO를 작성한다.
  2. 직렬화 프로세스를 실제로 수행하는 몇 줄의 코드를 작성한다.

이 기사에서는 필자의 기사에서 자주 사용되는 테마인 루어를 다시 한번 테마로 사용할 것이며 Listing 1이 바로 루어에 대한 정보를 나타내는 POJO이다.


Listing 1. Lure 클래스
@Root
public class Lure {

     @Attribute
     private String type;
	
     @Element
     private String company;
	
     @Element
     private int quantityInStock;
	
     @Element
     private String model;

     public String getType() {
		return type;
     }

     public void setType(String type) {
          this.type = type;
     }

     public String getCompany() {
          return company;
     }

     public void setCompany(String company) {
          this.company = company;
     }

     public int getQuantityInStock() {
          return quantityInStock;
     }

     public void setQuantityInStock(int quantityInStock) {
          this.quantityInStock = quantityInStock;
     }

     public String getModel() {
          return model;
     }

     public void setModel(String model) {
          this.model = model;
     }
}

이 POJO에는 복잡한 내용이 하나도 없다. 처음 봤을 때 어노테이션 부분이 익숙하지 않을 수도 있겠지만 이 또한 의도적인 것이다. Simple 프레임워크가 그 이름에 걸맞다고 한 필자의 말을 떠올려 보라.

@Root 어노테이션은 XML 문서의 루트 요소를 설명한다. 모든 XML 문서에는 루트 요소가 필요하므로 이 어노테이션을 반드시 포함시켜야 한다.

type 필드 위의 @Attribute 어노테이션은 해당 필드를 속성으로 식별한다. 이 속성은 루트 요소에 속성으로 추가된다.

마지막으로 남아 있는 @Element 어노테이션은 company, quantityInStockmodel이라는 세 필드의 바로 위에 사용된다. 이러한 필드는 XML 문서 내의 요소를 나타낸다.

POJO의 나머지 부분은 JavaBean 표준에 따라 접근자와 변경자로 구성되어 있다.

이제 POJO가 완료되었으므로 직렬화 코드를 작성할 차례이다. Listing 2에서 이 직렬화 코드를 볼 수 있다.


Listing 2. LureExample 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          Lure lure = new Lure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
		
          File result = new File("lure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

이 코드에서는 가장 먼저 Persister 오브젝트를 인스턴스화한다. 이 클래스는 Simple 프레임워크의 일부이고 Serializer 인터페이스를 구현한다.

그런 다음 Lure 오브젝트를 인스턴스화하고 필드를 적절히 설정한다. 여기에서는 루어를 제조하는 회사의 이름이 Donzai이고 모델 이름이 Marlin Buster이다. 재고량은 23개이다. 마지막으로 루어의 유형은 Trolling이다.

그런 다음 XML 문서가 될 파일의 이름을 사용하여 File 오브젝트를 인스턴스화한다. 이 경우에는 파일 이름이 lure.xml이다.

마지막으로 직렬 변환기를 호출하여 파일을 작성한다. write() 메소드에 두 개의 매개변수가 제공된다. 첫 번째 매개변수는 POJO이고 두 번째 매개변수는 File 오브젝트이다.

이제 이 코드를 실행할 수 있다. Listing 2는 Java 애플리케이션이므로 자주 사용하는 IDE(Integrated Development Environment)를 사용하여 코드를 실행할 수 있다. simple-xml-2.1.4.jar이 클래스 경로에 있는지 확인한다. Eclipse를 사용하는 경우에는 파일을 마우스 오른쪽 단추로 클릭하고 Run As를 선택한 다음 표시되는 메뉴에서 Java Application을 선택하면 된다.

애플리케이션이 정상적으로 작동했다면 Listing 3과 같은 결과 XML 문서가 생성되어야 한다. (당연히 정상적으로 작동되어야 하며 정말 간단한 작업이다.)


Listing 3. LureExample 출력
<lure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

Listing 3에서는 두 가지 사항에 주목해야 한다. 첫 번째는 루어 유형이 루트 요소의 속성이라는 것이다. 이는 @Element가 아닌 @Attribute를 사용하여 POJO의 type 필드를 어노테이트했기 때문에 완벽하게 작동한다.

결과 XML과 관련하여 또 하나 중요한 점은 요소 이름이 JavaBean 표준을 따른다는 것이다. 예를 들어, 루트 요소는 lure이고 클래스 이름은 Lure이다. 세 개의 하위 요소 이름도 해당 필드 이름과 완벽하게 일치한다. 다시 한번 말해서, 이 방법을 사용하면 루트 요소 이름과 하위 요소 이름이 서로 다른 패턴을 따르지 않아도 되기 때문에 이는 매우 실용적인 방법이다.

역직렬화하기

오브젝트를 직렬화하는 작업이 매우 쉬웠던 것처럼 역직렬화하는 방법도 매우 쉽다.

역직렬화는 XML 문서를 POJO로 변환하는 프로세스이다. 한 가지 좋은 점은 조금 전에 작성한 XML 문서를 역직렬화 작업에 사용할 수 있다는 것이다.

Listing 4에서는 역직렬화 코드를 보여 준다.


Listing 4. LureExample2 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          File source = new File("lure.xml");
          Lure lure = serializer.read(Lure.class, source);

          System.out.println(lure.getCompany());
          System.out.println(lure.getModel());
          System.out.println(lure.getQuantityInStock());
          System.out.println(lure.getType());
     } catch (Exception e) {
          e.printStackTrace();
     }
}

먼저 Serializer 인터페이스를 구현하는 Persister 오브젝트를 인스턴스화한다.

File 오브젝트를 인스턴스화하는 행도 익숙해 보이겠지만 이 경우에는 명확한 차이가 있다. Listing 3에서는 존재하지 않는 파일에 대한 File 오브젝트를 인스턴스화했지만 여기에서는 파일이 존재하고 있는 것으로 가정하고 있다. (실제로도 파일이 있어야 한다.)

그런 다음 Serializer 오브젝트의 read 메소드를 호출하여 POJO를 인스턴스화한다. read 메소드는 두 개의 매개변수를 사용한다. 하는 POJO 클래스이고 다른 하나는 데이터가 포함된 XML 파일을 나타내는 File 오브젝트이다.

마지막으로 모든 정보가 올바르게 읽혔는지 확인하기 위해 POJO의 모든 정보를 출력한다.

이 코드를 실행하면 Listing 5와 같은 출력이 표시되어야 한다.


Listing 5. LureExample2 출력
Donzai
Marlin Buster
23
Trolling

전체 트리 직렬화

지금까지 직렬화 및 역직렬화했던 XML 문서는 상당히 단순했다.

하지만 대부분의 XML 문서는 훨씬 더 복잡하다. 일반적으로 이러한 문서에는 중첩 요소뿐만 아니라 여러 개의 하위 요소를 가지고 있는 일대다 반복 요소가 여러 계층으로 포함되어 있다.

다행스럽게도 Simple은 그 이름에 걸맞게 복잡한 문서도 쉽게 처리할 수 있다. POJO 내에서 POJO를 중첩하는 것처럼 간단하게 처리할 수 있다. Listing 6을 살펴보자.


Listing 6. AdvancedLure 클래스
@Attribute
private String type;

@Element
private String company;
	
@Element
private int quantityInStock;
	
@Element
private String model;
	
@Element
private ConfigurationScheme configurationScheme;

Listing 6AdvancedLure 클래스는 Listing 1Lure 클래스와 매우 유사하다. 한 가지 차이점은 configurationScheme라는 또 하나의 필드가 포함되어 있다는 것이다. 구성 스키마는 Listing 7에서 설명하는 또 다른 POJO에 의해 표시된다.


Listing 7. ConfigurationScheme 클래스
@Root
public class ConfigurationScheme {
	
@Element
private String color;
	
@Element
private int size;

여기에서는 간단하게 설명하기 위해 접근자와 변경자를 생략했다.

Listing 7에서는 익숙한 어노테이션을 볼 수 있다. 이러한 어노테이션은 Listing 1에서 사용했던 것과 같은 어노테이션이다.

이제 Listing 8과 같은 결과를 얻을 수 있다.


Listing 8. LureExample3 클래스
public static void main(String[] args) {
     try {
          Serializer serializer = new Persister();
          AdvancedLure lure = new AdvancedLure();
          lure.setCompany("Donzai");
          lure.setModel("Marlin Buster");
          lure.setQuantityInStock(23);
          lure.setType("Trolling");
			
          ConfigurationScheme configurationScheme = new ConfigurationScheme();
          configurationScheme.setColor("Blue");
          configurationScheme.setSize(3);
          lure.setConfigurationScheme(configurationScheme);
			
          File result = new File("advancedlure.xml");
          serializer.write(lure, result);
     } catch (Exception e) {
          e.printStackTrace();
     }
}

Listing 2와 비교했을 때 Listing 8의 큰 차이점은 ConfigurationScheme 오브젝트를 인스턴스화한 다음 AdvancedLure 오브젝트의 해당 필드를 설정한다는 것이다.

이 코드를 실행하면 Listing 9와 같은 출력이 표시되어야 한다.


Listing 9. LureExample3 출력
<advancedLure type="Trolling">
   <company>Donzai</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
   <configurationScheme>
      <color>Blue</color>
      <size>3</size>
   </configurationScheme>
</advancedLure>

이 출력을 보면 중첩 요소가 예상대로 정확히 직렬화되었다는 것을 알 수 있다.

열거

XML 문서에는 특정 요소의 열거가 자주 사용된다. 즉, 동일한 요소 이름이 하위 또는 속성 데이터만 변경된 채로 반복해서 자주 사용된다. 다행히도 Simple은 이 상황을 잘 처리할 수 있다.

이 기능을 확인하기 위해 먼저 Inventory라는 새 클래스를 작성한다. 이 클래스에는 재고품이 보관되어 있는 창고의 이름과 해당 재고 창고에서 찾을 수 있는 루어의 목록이 있다(Listing 10 참조).


Listing 10. Inventory 클래스
@Root
public class Inventory {
	
     @ElementList
     private List<AdvancedLure> lures;
	
     @Attribute
     private String warehouse;

이 Listing에서는 @ElementList라는 새 어노테이션을 사용하고 있다. 이 어노테이션은 해당 List 오브젝트가 XML 요소의 열거를 나타낸다는 의미를 지닌다.

이 POJO의 직렬화를 보여 주기 위해 사용된 코드는 더 간단한 POJO(예: Listing 2에서 직렬화했던 POJO)를 직렬화하는 데 사용했던 코드와 마찬가지로 쉽게 이해할 수 있다. Listing 11을 살펴보자.


Listing 11. LureExample4 클래스
Serializer serializer = new Persister();

AdvancedLure lure = new AdvancedLure();
lure.setCompany("Donzai");
lure.setModel("Marlin Buster");
lure.setQuantityInStock(23);
lure.setType("Trolling");
			
ConfigurationScheme configurationScheme = new ConfigurationScheme();
configurationScheme.setColor("Blue");
configurationScheme.setSize(3);
lure.setConfigurationScheme(configurationScheme);
			
			
AdvancedLure lure2 = new AdvancedLure();
lure2.setCompany("Ziggi");
lure2.setModel("Tuna Finder");
lure2.setQuantityInStock(44);
lure2.setType("Trolling");
		
ConfigurationScheme configurationScheme2 = new ConfigurationScheme();
configurationScheme2.setColor("Red");
configurationScheme2.setSize(5);
lure2.setConfigurationScheme(configurationScheme2);
			
List<AdvancedLure> lures = new ArrayList<AdvancedLure>();
lures.add(lure);
lures.add(lure2);
			
Inventory inventory = new Inventory();
inventory.setLures(lures);
inventory.setWarehouse("Midwest");
			
File result = new File("inventory.xml");

serializer.write(inventory, result);

이 코드를 실행하면 inventory.xml이라는 XML 파일이 작성된다. 이 파일의 내용은 Listing 12와 같다.


Listing 12. LureExample4 출력
<inventory warehouse="Midwest">
   <lures>
      <advancedLure type="Trolling">
         <company>Donzai</company>
         <quantityInStock>23</quantityInStock>
         <model>Marlin Buster</model>
         <configurationScheme>
            <color>Blue</color>
            <size>3</size>
         </configurationScheme>
      </advancedLure>
      <advancedLure type="Trolling">
         <company>Ziggi</company>
         <quantityInStock>44</quantityInStock>
         <model>Tuna Finder</model>
         <configurationScheme>
            <color>Red</color>
            <size>5</size>
         </configurationScheme>
      </advancedLure>
   </lures>
</inventory>

이 Listing을 보면 Listing 11에서 인스턴스화하고 작성했던 POJO와 출력이 완전히 같다는 것을 알 수 있다. 두 개의 advancedLure 요소가 있고 각 요소에는 해당 POJO를 채우는 데 사용했던 데이터가 있다. 여기에서도 중첩이 적절히 사용되고 있다.

생성자

코드에서 변경되지 않는 POJO를 사용할 수 있다. 이 경우 setter 메소드를 사용하여 필드 속성을 수정하는 대신 생성자를 사용하여 이러한 값을 설정할 수 있다. Simple은 이 상황을 잘 처리할 수 있다.

이 경우에는 필드 이름 위가 아닌 생성자 매개변수 내에서 어노테이션을 지정한다. 해당 접근자 메소드 위에도 어노테이션이 필요하다. Listing 13을 살펴보자.


Listing 13. Inventory2 클래스
public Inventory2(@ElementList(name="lures") List<AdvancedLure> lures,
 @Attribute(name="warehouse") String warehouse) {
     this.lures = lures;
     this.warehouse = warehouse;
}

@ElementList(name="lures")
public List<AdvancedLure> getLures() {
     return lures;
}

@Attribute(name="warehouse")
public String getWarehouse() {
     return warehouse;
}

어노테이션을 생성자 매개변수의 일부로 지정할 경우에는 매개변수에 해당하는 필드 이름도 지정해야 한다. 첫 번째 매개변수에 대한 필드 이름은 lures이고 두 번째 매개변수에 대한 필드 이름은 warehouse이다.

그런 다음 접근자 메소드 위에 일치하는 어노테이션 및 필드 이름을 제공한다. lures에 대한 getter 바로 위에서 생성자에 사용된 어노테이션과 완전히 일치하는 해당 어노테이션을 볼 수 있다. 이와 마찬가지로 warehouse에 대한 getter 위의 어노테이션도 해당 어노테이션과 완전히 일치한다.

이 코드를 실행하기 위해 먼저 Listing 11을 약간 수정하여 Listing 14의 코드를 포함시킨다.


Listing 14. LureExample5 클래스
Inventory2 inventory = new Inventory2(lures,"MidWest");

여기에서는 Listing 11에서 사용했던 setter 메소드 대신 Listing 14의 코드를 사용하며 나머지 부분은 모두 동일하다.

템플리트 필터

XML 문서를 역직렬화할 때 템플리트 필터 또는 기본값을 사용할 수 있다는 점은 Simple의 또 다른 주요 기능이다.

이제 원래의 lure.xml로 돌아가서 Listing 15처럼 약간만 수정해 보자.


Listing 15. Lure2.xml 문서
<lure type="Trolling">
   <company>${lure.company}</company>
   <quantityInStock>23</quantityInStock>
   <model>Marlin Buster</model>
</lure>

이 문서의 company 요소에는 실제 회사의 이름 대신 Apache Ant 유형의 변수 선언이 포함되어 있으며 변수의 이름은 lure.company이다.

템플리트 필터를 사용하면 런타임에 변수 선언을 실제 값으로 대체하여 설정할 수 있다. 이를 수행하는 쉬운 방법으로는 변수 이름과 해당 값을 연결하는 Map 오브젝트를 사용하는 것이다. 그런 다음 Map 오브젝트를 사용하여 Simple 프레임워크에서 Filter 오브젝트를 생성한다. 그런 다음 Filter 오브젝트를 사용하여 Persister 오브젝트를 생성한다. Listing 16을 살펴보자.


Listing 16. LureExample6 클래스
Map<String,String> map = new HashMap<String,String>();
map.put("lure.company", "Monmouth");
Filter filter = new MapFilter(map);
			
Serializer serializer = new Persister(filter);
File source = new File("lure2.xml");

Lure lure = serializer.read(Lure.class, source);

System.out.println(lure.getCompany());
System.out.println(lure.getModel());
System.out.println(lure.getQuantityInStock());
System.out.println(lure.getType());

Listing 16Listing 2와 크게 다르지 않다. 주요 차이점은 String 값을 String 키에 연결하는 HashMap이 인스턴스화된다는 것이다. 이 경우 String 키는 예상대로 Listing 15에서 사용했던 변수 이름인 lure.company이다. 여기에서는 앞에서 보았던 XML 문서에 있던 값인 Donzai대신 Monmouth라는 값을 이 키에 지정한다.

이 코드를 실행하면 Listing 17과 같은 출력이 표시되어야 한다.


Listing 17. LureExample6 출력
Monmouth
Marlin Buster
23
Trolling

이 출력을 보면 템플리트 필터가 변수 이름 lure.companyMap 오브젝트에 있는 해당 키 이름에 연결된 실제 값으로 대체했다는 것을 알 수 있다. 이 출력은 예상과 정확히 일치한다.

결론

지금까지 살펴보았듯이 Simple은 강력한 XML 직렬화 및 역직렬화 프레임워크이며 사용하기도 쉽고, 구성도 필요하지 않기 때문에 빠른 개발이 가능하다.

Simple에는 여러 가지 강력한 기능이 있지만 여기에서는 지면의 제약으로 인해 일부 기능만을 살펴보았다. 소프트웨어 개발 작업 중에 XML 직렬화 및 역직렬화가 필요한 개발자라면 Simple을 사용해 보기를 적극 권장한다.



다운로드 하십시오

설명 이름 크기 다운로드 방식
Source code for the examples used in this article Simple.zip 5KB HTTP

다운로드 방식에 대한 정보

Posted by 1010
반응형

오래전부터 XML을 변환하는 데 있어서 XStream을 많이 사용했을 겁니다. 이것을 사용하면 아주 편하게 XML을 제어롤 하게 됩니다.(object를 xml로 or xml을 object로) 그래서 SOAP 인터페이스나 다양한 OPEN API나 멀티미디어 디바이스와의 연동 등에 많이 사용하곤 합니다.

아래의 샘플을 올려놓을테니 한번 실행해 보시고 사용법을 익힌다음 자기의 것으로 만들어 개발에 생산성을 높이는데 일조를 하시면 되겠죠. ^^

1. IXmlRule.java
package com.mimul.xstream;

public interface IXmlRule
{
public String toXML();

}

2. BaseRule.java
package com.mimul.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.Annotations;

import java.io.Serializable;
import java.lang.reflect.Field;


public class BaseRule implements Serializable {

/**
* XML 문자열로 변환
*/
protected String toXML() {
XStream xstream = new XStream();
Annotations.configureAliases(xstream, getClass());
Field[] fields = getClass().getDeclaredFields();
for (Field f : fields) {
Annotations.configureAliases(xstream, f.getType());
}
String xmlString = xstream.toXML(this);
xstream = null;
return xmlString;
}

/**
* XML 데이터로부터 Rule Build
*/
public static IXmlRule fromXML(String xmlString, Class clazz) {
XStream xstream = new XStream();
Annotations.configureAliases(xstream, clazz);
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
Annotations.configureAliases(xstream, f.getType());
}
IXmlRule rule = (IXmlRule) xstream.fromXML(xmlString);
xstream = null;
return rule;
}
}

3. Member.java
package com.mimul.xstream;

import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("xstream.Member")
public class Member {

private String accountNo;
private String password;


public String getAccountNo() {
return accountNo;
}

public void setAccountNo(String accountNo) {
this.accountNo = accountNo;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}
}

4. PersonRule.java
package com.mimul.xstream;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

import java.util.ArrayList;
import java.util.List;


@XStreamAlias("Person")
public class PersonRule extends BaseRule implements IXmlRule
{
private static final long serialVersionUID = 1L;

public String toXML() {
return super.toXML();
}

private String name;
private int age;
private String occupation;

@XStreamImplicit(itemFieldName = "members")
private List<Member> members;


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

public String getOccupation() {
return occupation;
}

public void setOccupation(String occupation) {
this.occupation = occupation;
}

public List<Member> getMembers() {
return members;
}

public void setMembers(List<Member> members) {
this.members = members;
}

public static void main(String args[])
{
PersonRule person = null;
List<Member> members = null;
Member member = null;

try {
person = new PersonRule();
person.setName("미물");
person.setAge(32);
person.setOccupation("Consultant");

members = new ArrayList<Member>(3);
member = new Member();
member.setAccountNo("mimul");
member.setPassword("mimuladmim");
members.add(member);

member = new Member();
member.setAccountNo("pepsi");
member.setPassword("pepsiadmin");
members.add(member);

member = new Member();
member.setAccountNo("scott");
member.setPassword("tigerda");
members.add(member);

person.setMembers(members);

// Object에서 XML 생성
String xmlString = person.toXML();
System.out.println("XML : " + xmlString);

// XML파일 Object 매핑
PersonRule personRule = (PersonRule) BaseRule.fromXML(xmlString, PersonRule.class);

System.out.println(personRule.getName());
System.out.println(personRule.getAge());
System.out.println(personRule.getOccupation());

for (Member mem : personRule.getMembers()) {
System.out.println(mem.getAccountNo());
System.out.println(mem.getPassword());
}
} catch (Exception e) {
System.out.println(e);
person = null;
members = null;
}
}
}

5. 실행 화면

Xstream
6. JSON 변환 방법을 알려면 여기를 가시면 됩니다.

출처 : http://mimul.com/pebble/default/2007/11/08/1194530400000.html
Posted by 1010
반응형
String t_xmlStr =           
   "<root>" +           
   "<item value=\"돈까스\">" +
   "<item value=\"순대국\">" +
   "<item value=\"짜장면\">" +
   "</item></item></item></root>";
   
  DocumentBuilderFactory t_dbf = null;       
  DocumentBuilder t_db = null;       
  Document t_doc = null;       
  NodeList t_nodes = null;       
  Node t_node = null;       
  Element t_element = null;       
  InputSource t_is = new InputSource();        
  try{           
   t_dbf = DocumentBuilderFactory.newInstance();           
   t_db = t_dbf.newDocumentBuilder();           
   t_is = new InputSource();           
   t_is.setCharacterStream(new StringReader(t_xmlStr));           
   t_doc = (Document) t_db.parse(t_is);           
   t_nodes = t_doc.getElementsByTagName("item");            
   for (int i = 0, t_len = t_nodes.getLength(); i < t_len; i ++){              
    t_element = (Element)t_nodes.item(i);                
    System.out.println(t_element.getAttribute("value"));   
    collection.add(new personVO(t_element.getAttribute("value"), t_element.getAttribute("value"), t_element.getAttribute("value")));
   }       
  }catch (Exception e){           
   e.printStackTrace();       
  }
Posted by 1010
반응형
:http://xstream.codehaus.org/tutorial.html <- 참조

Serializing an object to XML

Let's create an instance of Person and populate its fields:

Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));

Now, to convert it to XML, all you have to do is make a simple call to XStream:

String xml = xstream.toXML(joe);

The resulting XML looks like this:

<person>
  <firstname>Joe</firstname>
  <lastname>Walnes</lastname>
  <phone>
    <code>123</code>
    <number>1234-456</number>
  </phone>
  <fax>
    <code>123</code>
    <number>9999-999</number>
  </fax>
</person>

It's that simple. Look at how clean the XML is.

Posted by 1010
반응형

ThoughtWorks에서 만든 Xstream을 활용한다.
Xstream 최대의 장점은 초 간단...
얼마나 간단하면 튜토리얼이 Two Minute Tutorial 이다.
클래스 패스에 xstream-xxx.jar를 넣고.. 다음 코드를 실행하면..
XStream xstream = new XStream();
Person joe = new Person();
joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
String xml = xstream.toXML(joe);
System.out.println(xml);
출력 내용은.. 간단하기 이를데 없다.. 만족.. ^^
<object.Person>
<name>Joe</name>
<age>30</age>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</object.Person>
object.Person은 좀 보기 싫어.. 별칭(alias)를 준다.
XStream xstream = new XStream();
xstream.alias("person", Person.class);
Person joe = new Person();
joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
String xml = xstream.toXML(joe);
System.out.println(xml);
그럼.. 출력은 내 스타일(?)로 변모...
<person>
<name>Joe</name>
<age>30</age>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</person>
null값을 갖는 속성은 어찌 되는가?
XStream xstream = new XStream();
xstream.alias("person", Person.class);
Person joe = new Person();
// joe.setAge(30);
joe.setName("Joe");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
출력이 안되는군.
<person>
<name>Joe</name>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
</person>
XML을 자바 객체로..
XStream xstream = new XStream();
xstream.alias("person", Person.class);
String xml =
"<person>" +
"<name>Joe</name>" +
"<fax>" +
"<code>123</code>" +
"<number>9999-999</number>" +
"</fax>" +
"<phone>" +
"<code>123</code>" +
"<number>1234-456</number>" +
"</phone>" +
"</person>" ;
Person joe = (Person)xstream.fromXML(xml);
alias 처리를 포함해도 세 문장이면 되는구만.
단.. 자바 객체 변환(Deserializing)시에는 xpp.jar(xstream zip 파일의 lib에 있음)가 필요하다.
Posted by 1010
반응형

JAXB를 활용한 Java 객체의 XML 자동 변환

Using JAXB for XML data binding

자바 SE 6에서 JAXB(Java Architecture for XML Binding)를 사용하여 JAVA -> XML 변환하는 테스트 샘플을 만들어 보았습니다. 물론 XStream으로도 가능합니다.

1. JAXB란?
JAXB를 사용하면 XML과 자바 간에 쉽게 앞뒤로 이동할 수 있습니다. JAXB 구현은 XML 스키마를 받아 해당 스키마에 매핑되는 자바 클래스를 생성하는 스키마 컴파일러를 제공합니다. XML 문서의 데이터는 JAXB의 바인딩 런타임 프레임워크를 통해, 스키마 컴파일러가 생성한 클래스에 자동으로 바인딩될 수 있습니다. 이 작업을 언마샬링(Unmarshalling)이라고 합니다. 언마샬링되면 필요에 따라 콘텐츠를 Java로 조작하거나 수정할 수 있습니다. JAXB는 자바 개체에서 XML 인스턴스 문서로 데이터를 쓸(마샬링할) 수도 있습니다.

2. 샘플 소스
*. Person bean 객체
package client;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "person")
public class Person
{
private String firstName;
private String lastName;
private Family family;

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Family getFamily() {
return family;
}

public void setFamily(Family family) {
this.family = family;
}
}

*. Family bean 객체
package client;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;

public class Family
{
private String description;
@XmlElementWrapper(name = "persons")
@XmlElement
private List<Person> members = new ArrayList<Person>();


public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public List<Person> getMembers() {
return members;
}
}

*. Java객체를 Xml로 변환하는 클라이언트 샘플
package client;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

public class JAXBClient
{
public static void main(String[] args) {
JAXBContext context = null;
List<Person> list = null;
Person person1 = null;
Person person2 = null;
Family family = null;
Marshaller marshaller = null;

try {
context = JAXBContext.newInstance(Person.class);
list = new ArrayList<Person>();

person1 = new Person();
family = new Family();

family.setDescription("Family Mimul");
person1.setFirstName("IlDong");
person1.setLastName("Hong");
person1.setFamily(family);
list.add(person1);

person2 = new Person();
person2.setFirstName("LeeDong");
person2.setLastName("Hong");
person2.setFamily(family);
list.add(person2);

// Marshal 객체를 XML로 변환
// Unmarshal the objects from XML

marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
Boolean.TRUE);

marshaller.marshal(person2, System.out);

} catch (JAXBException e) {
e.printStackTrace();
}
}
}


3. 실행 결과
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<person>
<family>
<persons/>
<description>Family Mimul</description>
</family>
<firstName>LeeDong</firstName>
<lastName>Hong</lastName>
</person>
Posted by 1010
반응형

How to create XML file in Java – (JDOM Parser)
Published: August 4, 2011 , Updated: August 4, 2011 , Author: mkyong

In this example, we show you how to use JDOM parser to create document, element and attribute in a XML file.

1. XML File

At the end of this example, following XML file will be created.

File : file.xml

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1">
    <firstname>yong</firstname>
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>199999</salary>
  </staff>
  <staff id="2">
    <firstname>low</firstname>
    <lastname>yin fong</lastname>
    <nickname>fong fong</nickname>
    <salary>188888</salary>
  </staff>
</company>

3. JDOM Example

JDOM example to create above XML file.

import java.io.FileWriter;
import java.io.IOException;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
public class WriteXMLFile {
	public static void main(String[] args) {
 
	  try {
 
		Element company = new Element("company");
		Document doc = new Document(company);
		doc.setRootElement(company);
 
		Element staff = new Element("staff");
		staff.setAttribute(new Attribute("id", "1"));
		staff.addContent(new Element("firstname").setText("yong"));
		staff.addContent(new Element("lastname").setText("mook kim"));
		staff.addContent(new Element("nickname").setText("mkyong"));
		staff.addContent(new Element("salary").setText("199999"));
 
		doc.getRootElement().addContent(staff);
 
		Element staff2 = new Element("staff");
		staff2.setAttribute(new Attribute("id", "2"));
		staff2.addContent(new Element("firstname").setText("low"));
		staff2.addContent(new Element("lastname").setText("yin fong"));
		staff2.addContent(new Element("nickname").setText("fong fong"));
		staff2.addContent(new Element("salary").setText("188888"));
 
		doc.getRootElement().addContent(staff2);
 
		// new XMLOutputter().output(doc, System.out);
		XMLOutputter xmlOutput = new XMLOutputter();
 
		// display nice nice
		xmlOutput.setFormat(Format.getPrettyFormat());
		xmlOutput.output(doc, new FileWriter("c:\\file.xml"));
 
		System.out.println("File Saved!");
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  }
	}
}
Posted by 1010
반응형
How to modify XML file in Java – (JDOM Parser)
Published: April 3, 2010 , Updated: August 4, 2011 , Author: mkyong

JDOM XML parser example to modify an existing XML file :

  1. Add a new element
  2. Update existing element attribute
  3. Update existing element value
  4. Delete existing element

1. XML File

See before and after XML file.

File : file.xml – Original XML file.

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="1">
    <firstname>yong</firstname>
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>5000</salary>
  </staff>
</company>

Later, update above XML file via JDOM XML Parser.

  1. Add a new “age” element under staff
  2. Update the staff attribute id = 2
  3. Update salary value to 7000
  4. Delete “firstname” element under staff

File : file.xml – Newly modified XML file.

<?xml version="1.0" encoding="UTF-8"?>
<company>
  <staff id="2">
    <lastname>mook kim</lastname>
    <nickname>mkyong</nickname>
    <salary>7000</salary>
    <age>28</age>
  </staff>
</company>

2. JDOM Example

JDOM parser to update or modify an existing XML file.

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
 
public class ModifyXMLFile {
	public static void main(String[] args) {
 
	  try {
 
		SAXBuilder builder = new SAXBuilder();
		File xmlFile = new File("c:\\file.xml");
 
		Document doc = (Document) builder.build(xmlFile);
		Element rootNode = doc.getRootElement();
 
		// update staff id attribute
		Element staff = rootNode.getChild("staff");
		staff.getAttribute("id").setValue("2");
 
		// add new age element
		Element age = new Element("age").setText("28");
		staff.addContent(age);
 
		// update salary value
		staff.getChild("salary").setText("7000");
 
		// remove firstname element
		staff.removeChild("firstname");
 
		XMLOutputter xmlOutput = new XMLOutputter();
 
		// display nice nice
		xmlOutput.setFormat(Format.getPrettyFormat());
		xmlOutput.output(doc, new FileWriter("c:\\file.xml"));
 
		// xmlOutput.output(doc, System.out);
 
		System.out.println("File updated!");
	  } catch (IOException io) {
		io.printStackTrace();
	  } catch (JDOMException e) {
		e.printStackTrace();
	  }
	}
}

Posted by 1010
반응형

How to read XML file in Java – (JDOM Parser)
Published: December 21, 2009 , Updated: August 4, 2011 , Author: mkyong

JDOM is, quite simply, a Java representation of an XML document. JDOM provides a way to represent that document for easy and efficient reading, manipulation, and writing. It has a straightforward API, is a lightweight and fast, and is optimized for the Java programmer. It’s an alternative to DOM and SAX, although it integrates well with both DOM and SAX.

JDOM, Java XML parser, is more user friendly in the way of accessing the XML document.

In this example, we show you how to use JDOM to read a XML file, and print out each element orderly.

1. Download the JDOM library

JDOM is not like SAX or DOM, which bundled in JDK. To use JDOM, you need to download the library manually.

Get JDOM from JDOM official site or declares following dependency if you are using Maven.

    <dependency>
	<groupId>jdom</groupId>
	<artifactId>jdom</artifactId>
	<version>1.1</version>
    </dependency>

2. XML File

XML file as following

<?xml version="1.0"?>
<company>
	<staff>
		<firstname>yong</firstname>
		<lastname>mook kim</lastname>
		<nickname>mkyong</nickname>
		<salary>100000</salary>
	</staff>
	<staff>
		<firstname>low</firstname>
		<lastname>yin fong</lastname>
		<nickname>fong fong</nickname>
		<salary>200000</salary>
	</staff>
</company>

3. Java File

Use JDOM parser to parse above XML file.

import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
 
public class ReadXMLFile {
	public static void main(String[] args) {
 
	  SAXBuilder builder = new SAXBuilder();
	  File xmlFile = new File("c:\\file.xml");
 
	  try {
 
		Document document = (Document) builder.build(xmlFile);
		Element rootNode = document.getRootElement();
		List list = rootNode.getChildren("staff");
 
		for (int i = 0; i < list.size(); i++) {
 
		   Element node = (Element) list.get(i);
 
		   System.out.println("First Name : " + node.getChildText("firstname"));
		   System.out.println("Last Name : " + node.getChildText("lastname"));
		   System.out.println("Nick Name : " + node.getChildText("nickname"));
		   System.out.println("Salary : " + node.getChildText("salary"));
 
		}
 
	  } catch (IOException io) {
		System.out.println(io.getMessage());
	  } catch (JDOMException jdomex) {
		System.out.println(jdomex.getMessage());
	  }
	}
}

Output

First Name : yong
Last Name : mook kim
Nick Name : mkyong
Salary : 100000
First Name : low
Last Name : yin fong
Nick Name : fong fong
Salary : 200000
Posted by 1010
반응형


/*--

 Copyright (C) 2001 Brett McLaughlin.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.
 
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows
    these conditions in the documentation and/or other materials
    provided with the distribution.

 3. The name "Java and XML" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact brett@newInstance.com.
 
 In addition, we request (but do not require) that you include in the
 end-user documentation provided with the redistribution and/or in the
 software itself an acknowledgement equivalent to the following:
     "This product includes software developed for the
      'Java and XML' book, by Brett McLaughlin (O'Reilly & Associates)."

 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 */
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Properties;
import org.jdom.output.XMLOutputter;

/**
 * <b><code>PropsToXML</code></b> takes a standard Java properties
 *   file, and converts it into an XML format. This makes properties
 *   like <code>enhydra.classpath.separator</code> "groupbable" by
 *   "enhydra", "classpath", and by the key name, "separator", which
 *   the standard Java <code>java.util.Properties</code> class does
 *   not allow.
 */
public class PropsToXML {
   
    /**
     * <p> This will take the supplied properties file, and
     *   convert that file to an XML representation, which is
     *   then output to the supplied XML document filename. </p>
     *
     * @param propertiesFilename file to read in as Java properties.
     * @param xmlFilename file to output XML representation to.
     * @throws <code>IOException</code> - when errors occur.
     */
    public void convert(String propertiesFilename, String xmlFilename)
        throws IOException {
           
        // Get Java Properties object
        FileInputStream input = new FileInputStream(propertiesFilename);
        Properties props = new Properties();
        props.load(input);
       
        // Convert to XML
        convertToXML(props, xmlFilename);
    }        
   
    /**
     * <p> This will handle the detail of conversion from a Java
     *  <code>Properties</code> object to an XML document. </p>
     *
     * @param props <code>Properties</code> object to use as input.
     * @param xmlFilename file to output XML to.
     * @throws <code>IOException</code> - when errors occur.
     */
    private void convertToXML(Properties props, String xmlFilename)
        throws IOException {
   
        // Create a new JDOM Document with a root element "properties"
        Element root = new Element("properties");
        Document doc = new Document(root);
       
        // Get the property names
        Enumeration propertyNames = props.propertyNames();
        while (propertyNames.hasMoreElements()) {
            String propertyName = (String)propertyNames.nextElement();
            String propertyValue = props.getProperty(propertyName);
            createXMLRepresentation(root, propertyName, propertyValue);
        }        
       
        // Output document to supplied filename
        XMLOutputter outputter = new XMLOutputter("  ", true);
        FileOutputStream output = new FileOutputStream(xmlFilename);
        outputter.output(doc, output);
    }
   
    /**
     * <p> This will convert a single property and its value to
     *  an XML element and textual value. </p>
     *
     * @param root JDOM root <code>Element</code> to add children to.
     * @param propertyName name to base element creation on.
     * @param propertyValue value to use for property.
     */
    private void createXMLRepresentation(Element root,
                                         String propertyName,
                                         String propertyValue) {
       
        /*          
        Element element = new Element(propertyName);
        element.setText(propertyValue);
        root.addContent(element);
        */
       
        int split;
        String name = propertyName;
        Element current = root;
        Element test = null;
             
        while ((split = name.indexOf(".")) != -1) {
            String subName = name.substring(0, split);
            name = name.substring(split+1);
           
            // Check for existing element            
            if ((test = current.getChild(subName)) == null) {
                Element subElement = new Element(subName);
                current.addContent(subElement);
                current = subElement;
            } else {
                current = test;
            }
        }
       
        // When out of loop, what's left is the final element's name        
        Element last = new Element(name);                        
        // last.setText(propertyValue);
        last.setAttribute("value", propertyValue);
        current.addContent(last);
    }
                                       
    /**
     * <p> Provide a static entry point for running. </p>
     */
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("Usage: java PropsToXML " +
                "[properties file] [XML file for output]");
            System.exit(0);
        }
       
        try {
            PropsToXML propsToXML = new PropsToXML();
            propsToXML.convert(args[0], args[1]);
        } catch (Exception e) {
            e.printStackTrace();
        }        
    }
}
/*--

 Copyright (C) 2001 Brett McLaughlin.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.
 
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows
    these conditions in the documentation and/or other materials
    provided with the distribution.

 3. The name "Java and XML" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact brett@newInstance.com.
 
 In addition, we request (but do not require) that you include in the
 end-user documentation provided with the redistribution and/or in the
 software itself an acknowledgement equivalent to the following:
     "This product includes software developed for the
      'Java and XML' book, by Brett McLaughlin (O'Reilly & Associates)."

 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 */

/**
 * <b><code>XMLProperties</code></b> extends Java's
 *  <code>java.util.Properties</code> class, and provides
 *  behavior similar to properties but that use XML as the
 *  input and output format.
 */
class XMLProperties extends Properties {
   
    /**
     * <p> This overrides the default <code>load()</code>
     *   behavior to read from an XML document. </p>
     *
     * @param reader the reader to read XML from
     * @throws <code>IOException</code> - when errors occur reading.
     */
    public void load(Reader reader)
        throws IOException {
       
        try {
            // Load XML into JDOM Document
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(reader);
           
            // Turn into properties objects
            loadFromElements(doc.getRootElement().getChildren(),
                new StringBuffer(""));
           
        } catch (JDOMException e) {
            throw new IOException(e.getMessage());
        }        
    }    

    /**
     * <p> This overrides the default <code>load()</code>
     *   behavior to read from an XML document. </p>
     *
     * @param inputStream the input stream
     * @throws <code>IOException</code> - when errors occur reading.
     */
    public void load(InputStream inputStream)
        throws IOException {
         
        load(new InputStreamReader(inputStream));    
    }
   
    /**
     * <p> This overrides the default <code>load()</code>
     *   behavior to read from an XML document. </p>
     *
     * @param xmlDocument the XML document to read
     * @throws <code>IOException</code> - when errors occur reading.
     */
    public void load(File xmlDocument)
        throws IOException {
       
        load(new FileReader(xmlDocument));    
    }  
   
    /**
     * <p>This helper method loads the XML properties from a specific
     *   XML element, or set of elements.</p>
     *
     * @param elements <code>List</code> of elements to load from.
     * @param baseName the base name of this property.
     */
    private void loadFromElements(List elements, StringBuffer baseName) {
        // Iterate through each element
        for (Iterator i = elements.iterator(); i.hasNext(); ) {
            Element current = (Element)i.next();
            String name = current.getName();
            String text = current.getTextTrim();
            // String text = current.getAttributeValue("value");            
           
            // Don't add "." if no baseName
            if (baseName.length() > 0) {
                baseName.append(".");
            }            
            baseName.append(name);
           
            // See if we have an element value
            if ((text == null) || (text.equals(""))) {
                // If no text, recurse on children
                loadFromElements(current.getChildren(),
                                 baseName);
            } else {                
                // If text, this is a property
                setProperty(baseName.toString(),
                            text);
            }            
           
            // On unwind from recursion, remove last name
            if (baseName.length() == name.length()) {
                baseName.setLength(0);
            } else {                
                baseName.setLength(baseName.length() -
                    (name.length() + 1));
            }            
        }        
    }    
   
    /**
     * @deprecated This method does not throw an IOException
     *   if an I/O error occurs while saving the property list.
     *   As of the Java 2 platform v1.2, the preferred way to save
     *   a properties list is via the
     *   <code>{@link store(OutputStream out, String header}</code>
     *   method.
     */
    public void save(OutputStream out, String header) {
        try {            
            store(out, header);
        } catch (IOException ignored) {
            // Deprecated version doesn't pass errors
        }        
    }  
   
    /**
     * <p> This will output the properties in this object
     *   as XML to the supplied output writer. </p>
     *
     * @param writer the writer to output XML to.
     * @param header comment to add at top of file
     * @throws <code>IOException</code> - when writing errors occur.
     */
    public void store(Writer writer, String header)
        throws IOException {
           
        // Create a new JDOM Document with a root element "properties"
        Element root = new Element("properties");
        Document doc = new Document(root);
       
        // Add in header information
        Comment comment = new Comment(header);
        doc.getContent().add(0, comment);
       
        // Get the property names
        Enumeration propertyNames = propertyNames();
        while (propertyNames.hasMoreElements()) {
            String propertyName = (String)propertyNames.nextElement();
            String propertyValue = getProperty(propertyName);
            createXMLRepresentation(root, propertyName, propertyValue);
        }        
       
        // Output document to supplied filename
        XMLOutputter outputter = new XMLOutputter("  ", true);
        outputter.output(doc, writer);
        writer.flush();
    }    
   
    /**
     * <p> This will output the properties in this object
     *   as XML to the supplied output stream. </p>
     *
     * @param out the output stream.
     * @param header comment to add at top of file
     * @throws <code>IOException</code> - when writing errors occur.
     */
    public void store(OutputStream out, String header)
        throws IOException {
           
        store(new OutputStreamWriter(out), header);
    }
   
    /**
     * <p> This will output the properties in this object
     *   as XML to the supplied output file. </p>
     *
     * @param xmlDocument XML file to output to.
     * @param header comment to add at top of file
     * @throws <code>IOException</code> - when writing errors occur.
     */
    public void store(File xmlDocument, String header)
        throws IOException {
           
        store(new FileWriter(xmlDocument), header);
    }    
   
    /**
     * <p> This will convert a single property and its value to
     *  an XML element and textual value. </p>
     *
     * @param root JDOM root <code>Element</code> to add children to.
     * @param propertyName name to base element creation on.
     * @param propertyValue value to use for property.
     */
    private void createXMLRepresentation(Element root,
                                         String propertyName,
                                         String propertyValue) {
       
        int split;
        String name = propertyName;
        Element current = root;
        Element test = null;
             
        while ((split = name.indexOf(".")) != -1) {
            String subName = name.substring(0, split);
            name = name.substring(split+1);
           
            // Check for existing element            
            if ((test = current.getChild(subName)) == null) {
                Element subElement = new Element(subName);
                current.addContent(subElement);
                current = subElement;
            } else {
                current = test;
            }
        }
       
        // When out of loop, what's left is the final element's name        
        Element last = new Element(name);                        
        last.setText(propertyValue);
        /** Uncomment this for Attribute usage */
        /*
        last.setAttribute("value", propertyValue);
        */
        current.addContent(last);
    }                
}

/*--

 Copyright (C) 2001 Brett McLaughlin.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.
 
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows
    these conditions in the documentation and/or other materials
    provided with the distribution.

 3. The name "Java and XML" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact brett@newInstance.com.
 
 In addition, we request (but do not require) that you include in the
 end-user documentation provided with the redistribution and/or in the
 software itself an acknowledgement equivalent to the following:
     "This product includes software developed for the
      'Java and XML' book, by Brett McLaughlin (O'Reilly & Associates)."

 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 */

/**
 * <b><code>TestXMLProperties</code></b> is a simple class that tests
 *   usage of the <code>{@link XMLProperties}</code> class for reading
 *   XML property files.
 */
class TestXMLProperties {

    /**
     * <p>Provide a static entry point for testing.</p>
     */
    public static void main(String[] args) {
        if (args.length != 2) {
            System.out.println("Usage: java TestXMLProperties " +
                "[XML input document] [XML output document]");
            System.exit(0);
        }
   
        try {
            // Create and load properties
            System.out.println("Reading XML properties from " + args[0]);
            XMLProperties props = new XMLProperties();
            props.load(new FileInputStream(args[0]));
           
            // Print out properties and values
            System.out.println("\n\n---- Property Values ----");
            Enumeration names = props.propertyNames();
            while (names.hasMoreElements()) {
                String name = (String)names.nextElement();
                String value = props.getProperty(name);
                System.out.println("Property Name: " + name + 
                                   " has value " + value);
            }            
           
            // Store properties
            System.out.println("\n\nWriting XML properies to " + args[1]);
            props.store(new FileOutputStream(args[1]),
                "Testing XMLProperties class");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

// Demo file: enhydra.properties

/*

#
# This file has several Enhydra-specific properties
#   to make available to Java programs running with
#   knowledge of this properties file.
#

# sax parser implementing class
org.xml.sax.parser="org.apache.xerces.parsers.SAXParser"

# Class used to start the server
org.enhydra.initialclass=org.enhydra.multiServer.bootstrap.Bootstrap

# initial arguments passed to the server
org.enhydra.initialargs="./bootstrap.conf"

# Classpath for the parent top enhydra classloader
org.enhydra.classpath="."

# separator for the classpath above
org.enhydra.classpath.separator=":"


*/


           

Posted by 1010
반응형
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.util.Properties;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import java.util.Properties;
import java.util.Enumeration;
import org.apache.xerces.parsers.*;

public class ParseNonXML extends DefaultHandler {

  public static void main(String args[]) throws SAXException {

    PropertyFileParser pfp = new PropertyFileParser();
    pfp.setContentHandler(new ParseNonXML());
    pfp.parse(buildProperties());
  }

  public static Properties buildProperties() {
    Properties props = new Properties();
    for (int i = 0; i < 10; i++)
      props.setProperty("key" + i, "value" + i);
    return props;
  }

  public void startDocument() {
    System.out.println("<keys>");
  }

  public void endDocument() {
    System.out.println("</keys>");
  }

  public void characters(char[] data, int start, int end) {
    String str = new String(data, start, end);
    System.out.print(str);
  }

  public void startElement(String uri, String qName, String lName, Attributes atts) {
    System.out.print("<" + lName + ">");
  }

  public void endElement(String uri, String qName, String lName) {
    System.out.println("</" + lName + ">");
  }
}

class PropertyFileParser extends SAXParser {

  private Properties props = null;

  private ContentHandler handler = null;

  public void parse(Properties props) throws SAXException {
    handler = getContentHandler();
    handler.startDocument();
    Enumeration e = props.propertyNames();
    while (e.hasMoreElements()) {
      String key = (String) e.nextElement();
      String val = (String) props.getProperty(key);
      handler.startElement("", key, key, new AttributesImpl());
      char[] chars = getChars(val);
      handler.characters(chars, 0, chars.length);
      handler.endElement("", key, key);
    }
    handler.endDocument();
  }

  private char[] getChars(String value) {
    char[] chars = new char[value.length()];
    value.getChars(0, value.length(), chars, 0);
    return chars;
  }

}
Posted by 1010
반응형

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class MainClass {

  public static void main(String[] args) {

    try {
      Class.forName("COM.cloudscape.core.JDBCDriver").newInstance();

      Connection conn = DriverManager.getConnection("jdbc:cloudscape:GAMETRADER");

      Statement s = conn.createStatement();

      ResultSet rs = s.executeQuery("SELECT * FROM tableName");

      while (rs.next()) {
        int id = rs.getInt("ID");
        InputStream bis = rs.getAsciiStream("MANUAL");
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        int ch = 0;
        while ((ch = bis.read()) != -1)
          bos.write(ch);
        System.out.println("GAMEID: " + id + "\n" + "MANUAL: " + new String(bos.toByteArray()));
      }

    } catch (Throwable e) {
      System.out.println("exception thrown");
      System.out.println(e);
    }
  }
}




Posted by 1010
반응형


import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;

public class MainClass {

  public static void main(String[] args) throws Exception{
      Class.forName("COM.cloudscape.core.JDBCDriver").newInstance();

      Connection conn = DriverManager.getConnection("jdbc:cloudscape:GAMETRADER");

      conn.setAutoCommit(false);

      Statement s = conn.createStatement();
      s.executeUpdate("CREATE TABLE MANUALS(GAMEID INT, MANUAL LONG VARCHAR)");
      conn.commit();

      File file = new File("manuals.xml");
      InputStream is = new FileInputStream(file);

      PreparedStatement ps = conn.prepareStatement("INSERT INTO MANUALS VALUES(?,?)");

      ps.setInt(1, 1285757);

      ps.setAsciiStream(2, is, (int) file.length());

      ps.execute();
      conn.commit();
  }
}

Posted by 1010
반응형
import java.sql.*;
import java.io.*;
import org.apache.xerces.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;

public class XMLDBDOM {

  public static void main(String[] args) throws Exception{

      Class.forName("COM.cloudscape.core.JDBCDriver").newInstance();

      Connection conn = DriverManager.getConnection("jdbc:cloudscape:GAMETRADER");

      conn.setAutoCommit(false);

      Statement s = conn.createStatement();
      s.executeUpdate("CREATE TABLE XMLData(GAMEID INT, MANUAL SERIALIZE(org.w3c.dom.Document))");
      conn.commit();

      File file = new File("XMLData.xml");
      InputStream is = new FileInputStream(file);

      PreparedStatement ps = conn.prepareStatement("INSERT INTO XMLData VALUES(?,?)");

      ps.setInt(1, 1285757);

      DOMParser parser = new DOMParser();
      parser.parse("XMLData.xml");
      Document manual = parser.getDocument();
      ps.setObject(2, manual);

      ps.execute();

      conn.commit();
  }
}

Posted by 1010
반응형
출처 : http://www.ihelpers.co.kr
원저자 : 손상모

앞에서 배운 지식을 바탕으로 간단한 RSS Reader를 제작해 보도록 하겠습니다. 먼저 아래의 데모를 한번씩들 실행하여 보시기 바랍니다. 그리고 구독하고 있는 채널이 있다면 다른 RSS URL로 테스트도 해 보시구요. 아마도 해당 강좌를 보신 후에는 이 보다 멋진 RSS Reader(Aggregator)를 작성하실 수 있을 것입니다.

1. 데모보기

Simple RSS Reader - http://www.ihelpers.co.kr/lib/jmrss/simplereader.php?URL=http://rss.joins.com/joins_news_list.xml

2. URL 통신
저번 시간에는 RSS 파싱하는 방법에 대하여 소개를 하였습니다. 이번에는 RSS Reader 구현을 위한 URL 통신 방법과 그외의 핵심 기능에 대하여 알아보도록 하겠습니다.

그럼 URL로 RSS 구문을 어떻게 가지고 올까요?

저의 경우는 대부분의 경우는 HTTP 모듈을 사용하나, PHP에서는 fopen 함수를 사용하여 복잡한 과정 없이 웹상의 정보를 로컬디렉토리의 파일정보 처리하는 것 처럼 너무도 쉽게 구현 할수  있습니다.

HTTP의 헤더정보를 같이 좀더 세부적인 처리를 원하는 분은 소스코드에 포함된 "httpclass.php" 클래스를 분석해 보시기 바랍니다. 해당 강좌의 모든 코드는 HTTP 모듈을 사용하였습니다.

//$fd = fopen("http://www.ihelpers.co.kr", "r");
$fd = fopen("http://xmlmanager.egloos.com", "r");
while (!feof($fd)) {
$buffer .= fgets($fd, 4086);
}
fclose($fd);
echo $buffer;
?>
3. RSSReader Class
RSSReader 클래스는 RSSParser 클래스,URLCache 클래스,httpclass 클래스 사용하며, 특히 RSSParser 클래스를 상속받아 사용하고 있습니다. 클래스를 만들면서도 상속에 대한 문제점으로 사용여부를 두고 갈등을 했었지만, RSSParser에 포함된 GET 함수들을 모두 다시 작성할 생각을 하니 너무 귀찮아서 PHP에서 처음으로 상속을 사용해 보았습니다. 혹시 아직도 PHP에서 Class 나 상속기능을 사용해 보지 않으신 분은 참고하여 보시면 일정 부분 도움이 될것입니다.

RSSReader 변수(Property)

  • url - RSS URL정보
  • isCache - Cache 사용여부 ( true,false )
  • CacheDir - Cache 디렉토리
  • cacheInterval - Cache 갱신 주기
  • ErrNum - 에러번호
  • ErrMsg - 에러메세지
RSSReader 함수(method)
  • RSSReader - 생성자로써 URL정보,Cache사용여부,Cache 갱신주기, Cache 디렉토리를 변수로써 입력 받는다.
  • setCache - Cache 사용여부 설정
  • setCacheDir - Cache 디렉토리 설정
  • setCacheInterval - Cache 갱신 주기 설정
  • Read

    RSS Reader 클래스에서 가장 주요 업무인 HTTP 통신과 RSS 구문 분석을 수행하는 함수이니 RSSReader 클래스에서 가장 중요한 함수라고 할 수 있을 것입니다. Read 함수는 내부적으로 _getResponse를 호출하여 HTTP 통신을 수행하고, 부모 클래스의 parse 함수를 통하여 RSS 구문을 분석하여 줍니다.

  • _getResponse

    Cache 사용여부를 판단하고 Cache를 사용할 경우는 Cache된 파일의 최종수정시간과 설정된 갱신 주기를 비교하여 Cache의 갱신 및 조회여부를 판단하여 URL정보를 읽어오게 됩니다. Cache를 사용하지 않을 경우는 당연히 직접 자료를 조회하게 됩니다.

    if($status == 0){ // 캐쉬정보가 이전것일때
    $response = $cache->get($this->url);
    $http->AddHeader("If-Modified-Since",$response['last-modified']);
    $http->AddHeader("ETag",$response['etag']);
    }
    $http->Get($path);


    if($http->Response['code'] == 304){
    } elseif($http->Response['code'] == 200 || $http->Response['code'] == 304){
    $response = $http->Response;
    $cache->set($this->url,$response);
    } else {
    $this->Error(0,"Response Not Success");
    return false;
    }
    return $response;
  • 위의 코드는 조금 재미있게 볼 수 있을 것 같습니다. Cache 정보가 이전 것이라면 URL통신을 하여 새로운 정보를 가지고 와야 할 것입니다. 그 때 etag 와 last-modified를 포함하여 웹서버와 통신하여 URL 정보가 Cache된 정보와 비교하여 갱신이 되지 않았다면,웹서버는 상태코드로 304 를 리턴해 줍니다. 웹서버에 정보가 갱신이 되지 않았다면 RSS Reader쪽은 Cache정보를 갱신할 필요가 없고 웹서버에서는 URL에 해당하는 문서의 갱신상태만 파악하면 되기 때문에 좀 더 빠르게 통신을 할 수 있게 됩니다.

/*///////////////////////////////////////////////////////////////

작성자  : 손상모<smson@ihelpers.co.kr>
최초작성일 : 2004.10.27

변경내용  :

 2006.05.30 - 302 Object Moved 문제점 처리
 2006.05.30 - encoding 문제점 처리

http://www.ihelpers.co.kr

/////////////////////////////////////////////////////////////////*/

require_once("RSSParser.php");
require_once("URLCache.php");
require_once("httpclass.php");

/**
* RSS Reader Class
*
* RSS Format 읽기 기능 ( URLCache와 httpclass 이용 )
*
* @author Sang Mo,Son <smson@ihelpers.co.kr>
* @version 0.9 beta
* @access  public
*/
class RSSReader extends RSSParser {

 var $url;

 var $ErrNum;
 var $ErrMsg;

 var $isCache;

 var $CacheDir;

 var $cacheInterval;
   
 /**
     * Constructor
     *
     * @access public
  * @param string url
  * @param boolean Cache 유무
  * @param int  Cache 유효시간
     * @return void
     */
 function RSSReader($url,$isCache = true,$cacheInterval = 3600,$CacheDir = "./cache"){
  $this->url = $url;
  $this->isCache = $isCache;
  $this->cacheInterval = $cacheInterval;
  $this->CacheDir = $CacheDir;
  parent::RSSParser();
 }

 /**
     * Cache 유무 설정
     *
     * @access public
  * @param boolean Cache 유무
     * @return void
     */
 function setCache($isCache){
  $this->isCache = $isCache;
 }

 /**
     * Cache 디렉토리 설정
     *
     * @access public
  * @param string Cache 디렉토리
     * @return void
     */
 function setCacheDir($CacheDir){
  $this->CacheDir = $CacheDir;
 }

 /**
     * Cache 유효시간 설정
     *
     * @access public
  * @param int  Cache 유효시간
     * @return void
     */
 function setCacheInterval($cacheInterval){
  $this->cacheInterval = $cacheInterval;
 }

 /**
     * RSS 읽기
     *
     * @access private
     * @return boolean
     */
 function Read(){
  $response = $this->_getResponse();
  if($response){
   if(preg_match("/<\?xml.+encoding=\"(.+)\".+\?>/i",$response['body'],$match)){
    if(strtoupper($match[1]) == "UTF-8"){
     $response['body'] = iconv("UTF-8","EUC-KR",$response['body']);
     $response['body'] = str_replace("utf-8", "EUC-KR", $response['body']);
    }
   }
//   echo $response['body'];
   $this->parse($response['body']);
   return true;
  } else {
   return false;
  }
 }

 /**
     * RSS의 URL 또는 Cache 정보
     *
     * @access private
     * @return array response array
     */
 function _getResponse(){

  $aurl = parse_url($this->url);
  $host = $aurl["host"];
  $port = $aurl["port"];
  $path = $aurl["path"];
  if(!empty($aurl["query"])){
   $path = sprintf("%s?%s",$path,$aurl["query"]);
  }
  if(empty($port)){ $port = 80; }
  if(empty($path)){ $path = "/"; }


  if($this->isCache){
   $cache = new URLCache();
   $cache->setInterval($this->cacheInterval);
   $cache->setCacheDir($this->CacheDir);

   $status = $cache->checkCache($this->url);

   if($status == 1){     // 캐쉬정보가 새로운 것이라면
    $response = $cache->get($this->url);
    return $response;
   } else {
    $http = new HTTP($host,$port,10);
    if(!$http->Err){
     if($status == 0){   // 캐쉬정보가 이전것일때
      $response = $cache->get($this->url);
      $http->AddHeader("If-Modified-Since",$response['last-modified']);
      $http->AddHeader("ETag",$response['etag']);
     }
     $http->Get($path);

     if($http->Response['code'] == 302){
      $this->url = $http->Response['location'];
      $response = $this->_getResponse();
      return $response;
     } else {
      if($http->Response['code'] == 304){
      } elseif($http->Response['code'] == 200 || $http->Response['code'] == 304){
       $response = $http->Response;
       $cache->set($this->url,$response);
      } else {
       $this->Error(0,"Response Not Success");
       return false;
      }
      return $response;
     }
    } else {
     $this->Error(0,"Socket Connect Fail");
     return false;
    }
    $http->Close();
   }
  } else {

   $http = new HTTP($host,$port,10);
   if(!$http->Err){
    $buf = $http->Get($path);

    if($http->Response['code'] == 302){
     $this->url = $http->Response['location'];
     $response = $this->_getResponse();
     return $response;
    } else {
     if($http->Response['code'] == 200 || $http->Response['code'] == 304){
      return $http->Response;
     } else {
      $this->Error(0,"Response Not Success");
      return false;
     }
    }
   } else {
    $this->Error(0,"Socket Connect Fail");
    return false;
   }
   $http->Close();
  }
 }

    /**
     * 에러
     *
     * @access public
  * @param int  error number
  * @param string error message
     * @return void
     */
 function Error($errnum,$errmsg){
  $this->ErrNum = $errnum;
  $this->ErrMsg = $errmsg;
 }
}

4. URLCache에 대하여

브라우저가 Cache를 사용하지 않아 매번 접속시마다 변경이 잘 되지 않는 이미지를 다운로드 받아야 한다면 이처럼 웹이 발전되지 않았을 것입니다.

아마도 제작한 RSS Reader에서 Cache를 사용하지 않는다면, 채널을 구독하고 있는 사용자들의 주기적인 접속은 웹서버에 대한 공격으로 변신하여 웹서버 관리자의 얼굴을 하얗게 변하게 할 것입니다. 10,000명의 구독자에 의하여 프로그램이 1분 단위로 채널에 접속하여 정보의 갱신여부만 확인한다고 생각하면 이 만큼의 시스템 자원 낭비가 어디 있겠습니까?

RSS Reader의 경우는 시간이 많이 소요되는 Network 통신을 해야 하기에, 이 문제를 최소화 할 수 있는 Cache의 사용은 RSS Reader 프로그램 개발시에 상당히 중요한 부분이라고 생각합니다. Cache 사용은 "URL Cache를 사용하여 웹을 더욱 빠르게"  강좌와 소스코드에 포함되어 있는 URLCache 클래스를 참고하여 주십시요.

5. Simple RSS Reader

강좌 시작에서 본 간단한 RSS Reader 코드입니다.


include "RSSReader.php";
$url = $_GET["URL"];
$rss = new RSSReader($url,false);
echo "
echo "< style>\n?;
echo " echo " echo "
if(!empty($url)){
$response = $rss->Read();
if($response){
 $channel = $rss->getChannel();
 while (list($key, $value) = each ($channel)) {
  echo "\n?;
 }
  echo "
  $count = 0;
 foreach($rss->getItems() as $items){

  if($count == 0){
   $titles = $items;
   echo "    while (list($key, $value) = each ($titles)) {
    printf("
    }
    echo "    }
   echo "
   while (list($key, $value) = each ($items)) {
   printf("
   }
   echo "
   $count++;
  }
  echo "  }
}
echo "\n?;
?>

[ simplereader.php ]

6. 소스코드
Posted by 1010
반응형

XML Article

XML Beans : XMLBeans는 스키마 기반으로 XML 인포셋 전체에 커서 기반으로 접근할 수 있도록 하는 XML-Java binding tool이다. BEA Systems에 의해 개발 되었으며 2003년에 아파치 프로젝트에 기증 되었다. 기존의 SAX와 Dom등의 방식으로 XML 코딩을 하다 보니 코드 자체가 길어져 개발 및 유지보수하는데 어려움이 많았다. 이 같은 단점은 보완하기 위한 새로운 방법을 제시하고 있다.

XML 라이브러리

  • Xstream : 눈여겨 볼만한 놈.

XML 실전 프로그래밍

Posted by 1010
반응형

첨부파일이 아니라 내용에 붙였습니다

xmls x = new xmls(...)에서

x.domLoad(...);

....

x.domWrite(...);

이런 방식으로 사용하시면 됩니다

자세한 설명은 생략하겠습니다

xml의 구조에 대해서 조금만 아신다면 금방 파악이 되실 겁니다

상용으로 잘 사용하고 있습니다

붙이다 보니 tab이 먹지 않아서 정렬이 안되어 있는데

copy해서 editor에서 정리한 다음 보십시오


import java.io.*;
import java.util.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;

// xercesImpl.jar를 복사한다
// java_home/jre/lib/src.zip에 있음
import org.apache.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.*;
/*****
XML 문서의 구조
- 최상위 요소를 root라고 한다
  XML 문서는 단 하나의 root요소만을 가질 수 있다. 이를 흔히 top level이라고 한다
  root요소가 2개 이상일 경우에는 에러가 발생한다
- root요소 앞에는 XML 선언을 담고 있는 프롤로그가 올 수 있다
  XML 문서마다 사용된 XML 버전 정보를 프롤로그에 넣어주는것이 좋다
  <?xml version="1.0" ?>과 같이 버전 정보가 포함될 수 있다
  <?xml version="1.0" encoding="utf-8"?>
  <?xml version="1.0" encoding="euc-kr"?> encoding정보도 포함될 수 있다
  반드시 <?xml... 은 붙여야 한다
- 요소는 반드시 <와 >로 둘러싼 tag로 구성된다
  element와 attribute로 나뉘어 진다
  <tag>text</tag>
  <tag attribute="text">
  <tag attribute="text"></tag>
  <tag attribute="text"/>
  <tag></tag>
  <tag/>
- 주석은 <!--  -->이다

DOM (Document Object Model)
- XML문서를 메모리상에 올려놓은 다음 데이타를 찾아 들어가는 방식을 사용한다
- 큰 문서일경우 무조건 다 읽기 때문에 로드 시간이 걸리거나 메모리를 낭비하게 된다
- 문서 편집을 할 수 있다
- 데이타를 저장되어 있는 순서대로 받는다
SAX (Simple API for XML)
- 큰 문서를 효율적으로 분석하기 위해서 사용한다
- 이벤트가 발생하면 그에 해당하는 데이타를 추출한다. 속도가 DOM에 비해서 빠르다
- 읽기 전용이다. 문서를 편집할 수 없다
- 데이타를 SAX가 주는 순서대로 받는다. 파서가 문서를 탐색하는 순서에 대해서 어떠한 작업도 할 수 없다
- 원하는 요소만 골라서 읽을 수 있다
-----------------------------------------------------------------------------------------
현재 Java SAX Parser의 종류
- Xerces (Apache Foundation DOM & SAX)
  SAX와 DOMahen를 다룰 수 있게하는 XML API를 위하여 Apache Group의 프로젝트이다
  org.apache.xerces.parser를 사용한다
- Crimson (Sun Project X, JAXP Default Parser)
  Sun ProjectX의 일환으로 JAXP의 default parser로 채택되어져 있으며 XMLReader 인터페이스를 구현하므로
  SAX API를 이용하여 여러가지 다양한 파싱기능을 사용할 수 있다
- JAXP (Sun, Java API for XML Processing)
  Xerces처럼 DOM과 SAX 둘 다를 사용할 수 있도록 지원해주는 API이다
  한가지 다른점은 SAX API의 인터페이스를 직접 구현한 클래스를 제공하는것이 아니라
  abstract 계층을 한단계 얹은 형태를 제공한다
- Xalan은 xslt 프로세서이다. xsl을 이용하기 위해 필요하다
*****/

public class Xmls
{
 public static final int NONE = 0;
 public static final int DOM = 1;
 public static final int SAX = 2;
 // DOM
 private DocumentBuilderFactory dbFactory;
 private DocumentBuilder dBuilder;
 private Document document = null;
 private TransformerFactory tFactory;
 private Transformer transformer;
 // SAX
 private javax.xml.parsers.SAXParserFactory spFactory;
 private javax.xml.parsers.SAXParser sParser;
 private org.xml.sax.helpers.DefaultHandler defHandler;
// private SAXDbHandler defHandler = null;

 // type이 DOM이면 DOM방식으로 아니면 SAX 방식으로 처리한다
 public Xmls (int Type, boolean valid, org.xml.sax.helpers.DefaultHandler defHandler) throws Exception
 {
  if (Type == DOM)
      {
   dbFactory = DocumentBuilderFactory.newInstance();
   dbFactory.setValidating(valid);  // check를 넘겨주어도 된다
         dBuilder = dbFactory.newDocumentBuilder();
         // 출력할때 사용한다
   tFactory = TransformerFactory.newInstance();
         transformer = tFactory.newTransformer();
      }
  else
      {
         this.defHandler = defHandler;
         spFactory = javax.xml.parsers.SAXParserFactory.newInstance();
   sParser = spFactory.newSAXParser();
      // xslt 출력
//         TransformerFactory factory = TransformerFactory.newInstance();
//         Transformer transformer = factory.newTransformer(new SAXSource(new InputSource(stylesheetFile)));
//         transformer.transform(new SAXSource(new InputSource(XMLFilename)), new StreamResult(resultFilename));
      }
 }

 //******************** DOM 방식의 method
 // xml 문서를 읽는다
 // 버전 정보는 반드시 <?xml... 은 붙여야 한다. 아니면 에러가 발생한다
 public void domLoad (InputStream in) throws Exception
 {
  document = dBuilder.parse(in);
 }

 public void domLoad (String xmlPath) throws Exception
 {
  document = dBuilder.parse(new File(xmlPath));
 }

 public Document domGetDocument ()
 {
  return document;
 }

 // xml 문자열을 parsing한다
 // x.domParse("<node>가</node>");
 public void domParse (String xmlString) throws Exception
 {
  StringReader sr = new StringReader(xmlString);
  InputSource is = new InputSource(sr);

  document = dBuilder.parse(is);
 }

 // encoding이 null이거나 ""으면 setting하지 않는다
 public void domWrite (OutputStream out, String encoding) throws Exception
 {
  setEncoding(encoding);

  // javax.xml.transform.dom.
  DOMSource source = new DOMSource(document);
  StreamResult result = new StreamResult(out);
  transformer.transform(source, result);
 }

 public void domWrite (PrintWriter out, String encoding) throws Exception
 {
  StringWriter sw = new StringWriter();

  setEncoding(encoding);

  DOMSource source = new DOMSource(document);
  StreamResult result = new StreamResult(sw);
  transformer.transform(source, result);

  out.print(sw.toString());
 }

 // setEncoding("euc-kr");
 public void domWrite (String xmlPath, String encoding) throws Exception
 {
  setEncoding(encoding);

  // javax.xml.transform.dom.
  DOMSource source = new DOMSource(document);
  StreamResult result = new StreamResult(new File(xmlPath));
  transformer.transform(source, result);
 }

 // 모든 처리가 끝난 다음 마지막에 부른다
 public void domClose ()
 {
  this.document = null;
 }

 // element와 attribute를 새로 만들고 싶으면 아래의 순서대로 부른다
 // x.domAppendElement("personnel/person", "nation", "korea");
 // x.domAppendAttribute("personnel/person/nation", "capital", "서울");
 // node마다 각각의 값을 주기 위해서 String[] elementValue를 넘긴다
 public void domAppendAttribute (String xpath, String attrName, String[] attrValue) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  Element element;

  // append하기 때문에 attribute는 반드시 unique한 값을 가져야 하기 때문에 갯수가 맞지 않으면 에러를 발생시킨다
  if (nodes.getLength() != attrValue.length) throw new Exception("node 갯수와 value 갯수가 맞지 않습니다.");

  for (int i = 0; i < nodes.getLength(); i++)
      {
      element = (Element)nodes.item(i);
      element.setAttribute(attrName, attrValue[i]);
      }
 }

 // 해당 attribute node를 삭제하고 싶으면 domDeleteElement를 사용한다
 public void domDeleteAttribute (String xpath, String attrName) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  Element element;

  for (int i = 0; i < nodes.getLength(); i++)
   {
      element = (Element)nodes.item(i);
      element.removeAttribute(attrName);
      }
 }

 // elementValue가 없으면 text node를 append하지 않는다
 // x.domAppendElement("personnel/person", "nation", String[] k = { "korea" });
 // node마다 각각의 값을 주기 위해서 String[] elementValue를 넘긴다
 public void domAppendElement (String xpath, String elementName, String[] elementValue) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  Element element, element2;
  Text node;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      // loop안에서 선언한다. 모든 node에 append가 된다
   element = document.createElement(elementName);
   // nodes의 갯수와 elementValue의 갯수가 달라도 된다
      if (i < elementValue.length && Codes.checkNull(elementValue[i]) == false)
    {
    node = document.createTextNode(elementValue[i]);
          element.appendChild(node);
    }
      element2 = (Element)nodes.item(i);
      element2.appendChild(element);
      }
 }

 // x.domDeleteElement("personnel/person")
 // 하위 node 전체가 삭제된다
 public void domDeleteElement (String xpath) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  Node node;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      node = nodes.item(i);
      node.getParentNode().removeChild(node);  // 부모 노드에서 자식 노드(자신)를 삭제
      }
 }

 // xml 문자열을 파싱해서 해당 노드에 child로 붙인다
 // x.domAppendParse("personnel/person", "<node2><node3></node3></node2>");
 // x.domAppendAttribute("personnel/person/node2", "id", new String[] { "1", "2", "3", "4", "5", "6"  });
 // x.domAppendParse("personnel/person", "<node2><node3 id=\"1\">가</node3></node2>");
 public void domAppendParse (String xpath, String xmlString) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  Document tempDoc = makeTempDoc(xmlString);
  Node node;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      // loop안에 선언해야 한다.
   node = tempDoc.getDocumentElement();
   node = document.importNode(node, true);
      nodes.item(i).appendChild(node);
      }
 }

 // 기존의 노드에 값만 추가 시킨다
 // x.domAppendTextNode("personnel/person/node2/node3", "가");
 public void domAppendTextNode (String xpath, String[] txtValue) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  Text node;

  for (int i = 0; i < nodes.getLength(); i++)
      {
   // nodes의 갯수와 txtValue의 갯수가 달라도 된다
      if (i < txtValue.length && Codes.checkNull(txtValue[i]) == false)
    {
    node = document.createTextNode(txtValue[i]);
       nodes.item(i).appendChild(node);
    }
      }
 }

 // xpath="personnel/person/email"
 // attr, element 모두 xpath로 지정하면 갯수를 돌려준다
 public int domGetNodeCount (String xpath) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);

  return nodes.getLength();
 }

 // xpath="personnel/person", attr="id"
 // 해당 값의 index 값을 돌려준다. 중복값이 있으면 처음 발견되는 값의 index를 돌려준다
 public int domGetIndexAttribute (String xpath, String attrName, String attrValue) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  NamedNodeMap map;
  Node node, node2;
  String value = null;
  int idx = -1;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      node = nodes.item(i);
      map = node.getAttributes();
      node2 = map.getNamedItem(attrName);
      if (node2 != null && Codes.checkNull(attrValue) == false)
       {
          value = node2.getNodeValue();
       if (attrValue.equals(value)) { idx = i;  break;  }
       }
      }

  return idx;
 }

 public ArrayList domGetAttribute (String xpath, String attrName) throws Exception
 {
  return getAttribute(xpath, attrName, -1);
 }

 //** attr과 value의 갯수가 다를 수 있기 때문에 원하는 index의 attribute값이 아닐수도 있다
 // dom일 경우는 xml의 순서대로 읽어오기 때문에 index로의 처리가 가능하다
 public String domGetAttribute (String xpath, String attrName, int index) throws Exception
 {
  return (String)getAttribute(xpath, attrName, index).get(0);
 }

 // xpath="personnel/person", attr="id"
 public void domSetAttribute (String xpath, String attrName, String attrValue) throws Exception
 {
  setAttribute(xpath, attrName, null, new String[] { attrValue }, -1, 0);
 }

 // attribute는 unique하기 때문에 origs, news가 가능하다. index로 변경하지 않아도 된다
 // origValue는 원래 값, newValue는 새로운 값. origValue 값이 null이거나 ""이면 전체를 newValue 값으로 setting한다
 // 대소문자를 구분하고 싶지 않으면 외부에서 대소문자로 변환해서 넘겨준다
 public void domSetAttribute (String xpath, String attrName, String origValue, String newValue) throws Exception
 {
  setAttribute(xpath, attrName, origValue, new String[] { newValue }, -1, 0);
 }

 // 해당 index의 attribute를 수정한다
 public void domSetAttribute (String xpath, String attrName, String attrValue, int index) throws Exception
 {
  setAttribute(xpath, attrName, null, new String[] { attrValue }, index, 0);
 }

 // 기존의 attribute값을 변경한다
 public void domSetAttribute (String xpath, String attrName, String[] attrValue) throws Exception
 {
  setAttribute(xpath, attrName, null, attrValue, -1, attrValue.length);
 }

 // xpath에 해당하는 값이 여러개이면 여러개 하나면 하나만 돌려준다
 // xpath="personnel/person/email"
 public ArrayList domGetValue (String xpath) throws Exception
 {
  return getValue(xpath, -1);
 }

 //** attr과 value의 갯수가 다를 수 있기 때문에 원하는 index의 attribute값이 아닐수도 있다
 // dom일 경우는 xml의 순서대로 읽어오기 때문에 index로의 처리가 가능하다
 public String domGetValue (String xpath, int index) throws Exception
 {
  return (String)getValue(xpath, index).get(0);
 }

 // domSetAttribute하고 다르다. attribute는 unique하기 때문에 origs, news가 가능하다
 // xpath="personnel/person/email"
 public void domSetValue (String xpath, String value) throws Exception
 {
  setValue(xpath, new String[] { value }, -1, 0);
 }

 //** attr과 value의 갯수가 다를 수 있기 때문에 원하는 index의 attribute값이 아닐수도 있다
 // dom일 경우는 xml의 순서대로 읽어오기 때문에 index로의 처리가 가능하다
 public void domSetValue (String xpath, String value, int index) throws Exception
 {
  setValue(xpath, new String[] { value }, index, 0);
 }

 public void domSetValue (String xpath, String[] value) throws Exception
 {
  setValue(xpath, value, -1, value.length);
 }

 // domWrite할때 사용한다
 // setEncoding("euc-kr");
 private void setEncoding (String encoding)
 {
  if (Codes.checkNull(encoding)) return;

  transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
  transformer.setOutputProperty(OutputKeys.INDENT, "yes");
 }

 private Document makeTempDoc (String nodeString) throws Exception
 {
  StringReader sr = new StringReader(nodeString);
  InputSource is = new InputSource(sr);

  return dBuilder.parse(is);
 }

 private ArrayList getAttribute (String xpath, String attrName, int index) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  NamedNodeMap map;
  Node node, node2;
  ArrayList al = new ArrayList();
  String value = null;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      if (index >= 0 && i != index) continue;

      node = nodes.item(i);
      map = node.getAttributes();      // 같은 node를 찾는다
      node2 = map.getNamedItem(attrName);
      if (node2 != null)
    {
       value = node2.getNodeValue();
          al.add(value);
    }
      }

  return al;
 }

 private void setAttribute (String xpath, String attrName, String attrValue, String[] setValue, int index, int length) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  NamedNodeMap map;
  Node node, node2;
  String value = null;
  int off;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      if (length > 0 && i >= length) break;
   if (index >= 0 && i != index) continue;

      node = nodes.item(i);
      map = node.getAttributes();
      node2 = map.getNamedItem(attrName);
   off = (length > 0) ? i : 0;
      if (node2 != null)
    {
       if (index > -1 || Codes.checkNull(attrValue)) node2.setNodeValue(setValue[off]);
          else
        {
           value = node2.getNodeValue();
        if (attrValue.equals(value)) { node2.setNodeValue(setValue[off]);  break; }
        }
    }
      }
 }

 private ArrayList getValue (String xpath, int index) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  NodeList children;
  Node node;
  Node childNode;
  ArrayList al = new ArrayList();
  // value를 리턴하기 위해서 string 변수를 선언
  String value = null;

  // 여러개의 element에서 하나의 태그가 빠지면 nodes.getLength()의 갯수가 아예 줄어든다
  // al.add(Integer.toString(nodes.getLength()));
  for (int i = 0; i < nodes.getLength(); i++)
      {
   if (index >= 0 && i != index) continue;

      node = nodes.item(i);
      if (node.hasChildNodes())
    {
    // child node가 있는 node type은 element와 document뿐이다
    if (node.getNodeType() == Node.ELEMENT_NODE)
        {
     // Element 인 경우에는 자식노드를 검색해서 자식 노드중 텍스트 노드, 그러니까
     // 태그 사이의 텍스트 값을 리턴하자 일단.
        children = node.getChildNodes();
        for (int j = 0; j < children.getLength(); j++)
         {
      childNode = children.item(j);
      if (childNode.getNodeType() == Node.TEXT_NODE)
          {
       // 자식노드를 순환하다가 TextNode 발견하면 value로 세팅.
       // out.println(childNode.getNodeName());
          value = childNode.getNodeValue();
          al.add(value);
          }
      }
        }
    else
        {
        /*
        <personnel>
          <person id="Big.Boss">
            <name><family>Boss</family> <given>Big</given></name>
            <email>chief@foo.com</email>
            <link subordinates="one.worker two.worker three.worker four.worker five.worker"/>
          </person>
        </personnel>
        -- person이나 name일 경우 값이 없다.
        */
     // Document 인 경우에는 Node value라는 개념이 애매하니까..
     // 전체 String 을 리턴하거나 null값을리턴해야 하는데 일단 null을 리턴하기로 하자.
     // Do nothing
        }
    }
      else
    {
    // 자식노드가 없는 Attribute나 Text노드, CDATASection등의 값을 질의한 경우. getNodeValue를 이용.
    value = node.getNodeValue();
    al.add(value);
    }
      }

  return al;
 }

 private void setValue (String xpath, String[] value, int index, int length) throws Exception
 {
  NodeList nodes = XPathAPI.selectNodeList(document, xpath);
  NodeList children;
  Node node;
  int off;

  for (int i = 0; i < nodes.getLength(); i++)
      {
      if (length > 0 && i >= length) break;
   if (index >= 0 && i != index) continue;

      off = (length > 0) ? i : 0;
      node = nodes.item(i);
      if (node.hasChildNodes())
    {
    // 기존 Text노드를 삭제하고 다시 setting해야 한다
    // 삭제하지 않으면 기존값에 새로운값이 붙여서 처리된다
    children = node.getChildNodes();
    for (int j = 0; j < children.getLength(); j++)
        {
        if (children.item(j) instanceof Text) node.removeChild(children.item(j));
        }
    if (node.getNodeType() == Node.ELEMENT_NODE) node.appendChild((Text)document.createTextNode(value[off]));
    else                                         node.setNodeValue(value[off]);
    }
      else
    {
    /*
    자식노드가 없는 Attribute나 Text노드, CDATASection등의 값을 질의한 경우.
    person, link인 경우에 해당
       <personnel>
         <person id="Big.Boss">
           <name><family>Boss</family> <given>Big</given></name>
           <email>chief@foo.com</email>
           <link subordinates="one.worker two.worker three.worker four.worker five.worker"/>
         </person>
       </personnel>
    */
    if (node.getNodeType() == Node.ELEMENT_NODE) node.appendChild((Text)document.createTextNode(value[off]));
    else                                         node.setNodeValue(value[off]);
    }
      }
 }

 //******************** SAX 방식의 method
    // defHandler는 saxLoad를 부를때 외부에서 받는다
 // overriding을 해야 하기 때문에 외부에서 defHandler를 control을 할 수 있게 한다.
 public void saxLoad (InputStream in) throws Exception
 {
  sParser.parse(in, defHandler);
 }

 public void saxLoad (String xmlPath) throws Exception
 {
     sParser.parse(new File(xmlPath), defHandler);
 }

 public org.xml.sax.helpers.DefaultHandler saxGetDefHandler ()
 {
  return defHandler;
 }
}

Posted by 1010
반응형

이 글에서는 Java 2 Java 2, Enterprise Edition, v 1.4 를 사용합니다. 다운로드



SUN JAVA STREAMING XML PARSER 소개

XML을 사용하는 대부분의 Java 개발자는 SAX (Simple API for XML) 라이브러리와 DOM(Document Object Model) 라이브러리에 익숙할 것이다. SAX는 이벤트 기반의 API이며, 이는 일반적으로 프로그래머가 파서와 몇 개의 리스너를 등록하고, 특정 XML 문법 생성자(예를 들어 요소나 속성)가 도착되면 리스너 메소드가 호출된다는 의미이다. 그 반대로 DOM은 트리 기반의 아케텍처를 가지며, 전체 문서를 스캔하여 마주치는 각각의 문법 생성자의 오브젝트 트리를 구축한다. 프로그래머는 스캔이 완료된 후 오브젝트 트리에 접근하여 수정할 수 있다

이 두 방법 모두 각각의 결점을 가지고 있다: 리스너를 이용하는 이벤트 기반의 API는 일반적으로 다루기 힘들다. 리스너들이 파서에 의해 조종되기 때문이다. 트리 기반의 API는 스캔되는 문서의 양에 비해 과도한 양의 메모리를 소모할 수 있다. 이제 Java 개발자들이 XML 을 스캔하는데 이용할 수 있는 세 번째 API가 등장하였다. StAX (Streaming API for XML parse)가 그것이다.

SJSXP란?

SJSXP(Sun Java Streaming XML Parser)는 StAX를 빠른 속도로 구현한다. 썬마이크로시스템즈와 협력하고 있는 BEA Systems, XML-guru James Clark, Stefan Haustein, Aleksandr Slominski (XmlPull 개발자들), 그리고 JCP의 다른 멤버들은 JSR 173를 구현하는 것으로써 StAX를 개발하였다. StAX은 공유 인터페이스들에 기반하는, 파서(parser) 독립적인 Java API이다.

SJSXP는 Java Web Services Developer Pack v1.5에 포함되어있다. SJSXP에 대해 처음으로 알아차릴만한 것은 이것이 스트림 API에 기반한다는 것이다. 즉, 개발자가 어느 한 노드에 접근하기 위해 전체 문서를 읽을 필요가 없다. 또한, 파서를 시작하여 파서가 데이터를 이벤트 리스너 메소드에 "push"하도록 허용하는 법칙을 따르지 않는다. 대신에 SJSXP는 "pull" 메소드를 구현하며, 이 메소드는 정렬 포인터를 문서에서 현재 스캔되고 있는 지점에 유지한다. 이는 종종 커서(cursor)라고 불린다. 사용자는 단순히 커서가 현재 가리키고 있는 노드에 대한 파서를 요청하면 된다.

XML 문서 파싱에 SJSXP 이용하기

SJSXP를 이용하여 XML 문서를 읽는 것은 아주 쉽다. 대부분의 작업은 javax.xml.stream.XMLStreamReader 인터페이스를 구현하는 오브젝트를 통해 이뤄진다. 이 인터페이스는 XML 문서의 첫 부분에서 마지막까지 이동되는 커서를 나타낸다. 몇 가지 명심해야할 것이 있다. 커서는 항상 하나의 아이템(시작 태그 요소, 진행 명령, DTD 선언 등)만을 가리켜야 한다. 또한 커서는 항상 앞으로 움직여야 하며 (뒤로 움직일 수 없다), 다음에 무엇이 나타나는지 미리 보기를 실행할 수 없다. 다음의 코드 발췌에서 파일로부터 XML을 읽는 XMLStreamReader를 얻을 수 있다.

   URL url = Class.forName("MyClassName").getResource(
           "sample.xml");            
   InputStream in = url.openStream();
   XMLInputFactory factory = XMLInputFactory.newInstance();
   XMLStreamReader parser = factory.createXMLStreamReader(in);

그 후 다음 코드를 이용하여 XML 파일을 반복할 수 있다.

   while(parser.hasNext()) {
             
         eventType = parser.next();
         switch (eventType) {

              case START_ELEMENT:
              //  Do something
              break;
              case END_ELEMENT:
              //  Do something
              break;
              //  And so on ...
         }
     }

XMLStreamReaderhasNext() 메소드는 XML 파일에서 또다른 유효한 아이템이 있는지 확인한다. 만약 있다면, 커서가 다음 아이템으로 넘어가게하기 위해 next() 메소드를 사용할 수 있다. next() 메소드는 만나게되는 문법상 생성자(아이템)의 타입을 가리키는 인티거 코드를 리턴한다.

XMLInputStreamReader에는 몇 개의 get 메소드가 있어서 커서가 가리키는 XML 아이템의 내용을 얻는 데 사용할 수 있다. 첫번째 메소드는 getEventType()이다:

   public int getEventType()

메소드는 커서가 있는 곳에서 파서가 찾은 아이템의 타입을 식별하는 integer 코드를 리턴한다. next() 메소드에 의해 리턴되는 것과 같은 코드이다. 아이템은 XMLInputStream 상수 중 하나에 의해 식별된다.

  XMLStreamConstants.START_DOCUMENT 
  XMLStreamConstants.END_DOCUMENT 
  XMLStreamConstants.START_ELEMENT 
  XMLStreamConstants.END_ELEMENT 
  XMLStreamConstants.ATTRIBUTE 
  XMLStreamConstants.CHARACTERS 
  XMLStreamConstants.CDATA 
  XMLStreamConstants.SPACE 
  XMLStreamConstants.COMMENT 
  XMLStreamConstants.DTD 
  XMLStreamConstants.START_ENTITY 
  XMLStreamConstants.END_ENTITY 
  XMLStreamConstants.ENTITY_DECLARATION 
  XMLStreamConstants.ENTITY_REFERENCE 
  XMLStreamConstants.NAMESPACE 
  XMLStreamConstants.NOTATION_DECLARATION 
  XMLStreamConstants.PROCESSING_INSTRUCTION 

만약 아이템에 이름이 있는 경우, getName()getLocalName() 메소드를 사용하여 이름을 얻을 수 있다. 후자는 어떤 다른 정보(예; 확인된 네임스페이스가 없는 요소의 이름) 없이 이름 자체를 산출한다.

   public Qname getName()
   public String getLocalName()

만약 당신이 현재 아이템의 네임스페이스를 식별하고 싶다면 getNamespaceURI() 메소드를 사용 할 수 있다.

   public String getNamespaceURI()

만약 DTD 선언 내의 텍스트나 요소 안의 텍스트 등과 같은 동반되는 텍스트가 있을 때에는 다음 메소드들을 사용하여 얻을 수 있다.(후자는 요소를 위해 단독으로 사용 될 수 있다)

   public String getText()
   public String getElementText()

만약 요소가 그것과 관계 되는 속성을 가진다면 getAttributeCount() 메소드를 사용하여 현재 요소가 가진 속성들의 갯수를 얻을 수 있다. 그 후 getAttributeName()getAttributeValue() 메소드를 사용하여 각각의 정보를 검색 할 수 있다.

   public int getAttributeCount()
   public Qname getAttributeName(int index)
   public String getAttributeValue(int index)

만약 속성의 로컬 이름과 요소의 네임스페이스 URI를 안다면, 또한 다음의 메소드를 이용하여 속성값을 얻을 수 있다.

   public String getAttributeValue(
     String elementNamespaceURI, String localAttributeName) 

추측했겠지만, 모든 접근자 메소드가 특정 상태에 적용가능한 것이 아니다. 예를 들어, 현재 DTD를 프로세싱 중이라면 getElementText()을 호출할 수 없다. 만약 이를 호출한다면, 파서가 충돌하는 이벤트 타입을 식별했다는 XMLStreamException을 얻게 되거나 메소드가 스스로 널(null) 값을 리턴하게 될 것이다.

XMLInputFactory 클래스의 setProperty() 메소드를 사용하여 몇 가지 파서 속성을 시작할 수 있다. 예를 들어, 다음은 파서와 마주치는 엔티티 레퍼런스는 교체될 것이라고 지정한다.

   factory.setProperty(
     XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, 
       Boolean.TRUE);

파서가 외부 엔티티를 지원하는 것을 막기 위해 다음과 같이 설정한다.

   factory.setProperty(
     XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, 
       Boolean.FALSE);

파서가 네임스페이스를 알아차리게하기 위해 다음과 같이 설정한다.

   factory.setProperty(
     XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.TRUE);

SJSXP의 현재 버전에서는 다음의 명령은 허용되지만 파서는 확인되지 않는다는 것을 유의하기 바란다.

   factory.setProperty(XMLInputFactory.IS_VALIDATING, 
     Boolean.TRUE);

만약 이 XMLInputFactory 특성들 중 어느 하나라도 가능하게 된다면 setXMLReporter() 메소드를 사용하여 파서가 만나게되는 오류를 제어할 수 있다. 파서가 만나는 오류의 타입을 가장 빨리 정확하게 결정할 수 있는 방법은 setXMLReporter() 메소드와 상호 작용하는 익명의 이너 클래스를 사용하는 것이다. 이는 다음과 같다.

   factory.setXMLReporter(new XMLReporter() {
     public void report(String message, String errorType,
       Object relatedInformation, Location location) {
         System.err.println("Error in " 
          + location.getLocationURI());
         System.err.println("at line " 
          + location.getLineNumber()
          + ", column " + location.getColumnNumber());
         System.err.println(message);
     }
   });

XML 문서 작성에 SJSXP 사용하기

XML 결과를 작성하는 것은 SJSXP를 이용하면 쉽다. 이 경우, XMLStreamReader 인터페이스 대신에 XMLStreamWriter 인터페이스를 사용할 수 있다. XMLStreamWriter 인터페이스는 작성하는 요소, 속성, 코멘트, 텍스트를 비롯해 XML 문서의 모든 부분을 작성하기 위한 직접적인 메소드를 제공한다. 다음의 예제에서는 어떻게 이 인터페이스를 얻어서 XML 문서를 작성하는데 사용하는지 보여준다.

   XMLOutputFactory xof =  XMLOutputFactory.newInstance();
   XMLStreamWriter xtw = 
     xof.createXMLStreamWriter(new FileWriter("myFile"));

   xtw.writeComment(
     "all elements here are in the HTML namespace");
   xtw.writeStartDocument("utf-8","1.0");
   xtw.setPrefix("html", "http://www.w3.org/TR/REC-html40");
   xtw.writeStartElement(
     "http://www.w3.org/TR/REC-html40","html");
   xtw.writeNamespace(
     "html", "http://www.w3.org/TR/REC-html40");
   xtw.writeStartElement(
     "http://www.w3.org/TR/REC-html40","head");
   xtw.writeStartElement(
     "http://www.w3.org/TR/REC-html40","title");
   xtw.writeCharacters("Java Information");
   xtw.writeEndElement();
   xtw.writeEndElement();

   xtw.writeStartElement(
     "http://www.w3.org/TR/REC-html40","body");
   xtw.writeStartElement("http://www.w3.org/TR/REC-html40","p");
   xtw.writeCharacters("Java homepage is ");
   xtw.writeStartElement("http://www.w3.org/TR/REC-html40","a");
   xtw.writeAttribute("href","http://java.sun.com");
   xtw.writeCharacters("here");
   xtw.writeEndElement();
   xtw.writeEndElement();
   xtw.writeEndElement();
   xtw.writeEndElement();
   xtw.writeEndDocument();

   xtw.flush();
   xtw.close();

각 요소를 작성하는 것이 끝나면 사용자는 라이터(writer)를 날려보내고 닫아야한다.

이전의 코드는 다음의 XML로 결과가 나타난다.(여기서는 쉽게 읽을 수 있게 라인 별로 나타내었다.)

   <!--all elements here are explicitly in the HTML namespace-->
   <?xml version="1.0" encoding="utf-8"?>
   <html:html xmlns:html="http://www.w3.org/TR/REC-html40">
   <html:head>
   <html:title>Java Information</html:title>
   </html:head>
   <html:body>
   <html:p>
   Java information is 
   <html:a href="http://frob.com">here</html:a>
   </html:p>
   </html:body>
   </html:html>

XML 문서 필터링

만약 각각의 아이템 타입을 스캔하고 싶지 않다면 들어오는 XML 문서에 대한 필터를 생성할 수 있다. 이를 위해서는 javax.xml.stream.StreamFilter 인터페이스를 구현하는 클래스를 생성한다. 이 인터페이스는 단지 accept() 메소드만으로 구성된다. 이 메소드는 XMLStreamReader 오브젝트를 허용하고 원시 Boolean을 리턴한다. StreamFilter의 일반적인 구현은 다음과 같다.

   public class MyStreamFilter implements StreamFilter {

       public boolean accept(XMLStreamReader reader) {
           if(!reader.isStartElement() && !reader.isEndElement())
               return false;
           else
               return true;
       }
   }

그 다음으로 XMLInputFactorycreateFilteredReader() 메소드를 호출하여 필터링된 리더(reader)를 생성하고 이를 원래 XML 스트림 리더와 StreamFilter 구현에 모두 전달한다. 다음과 같다.

   factory.createFilteredReader(
     factory.createXMLStreamReader(in), new MyStreamFilter());

SJSXP의 더 자세한 정보는 Sun Java Streaming XML Parser release notes를 참고하기 바란다.

Sun Java Streaming XML Parser 예제 코드 구동하기

  1. 이번 테크팁에 대한 샘플 아카이브(ttfeb2005sjsxp.jar)를 다운로드한다.

  2. Java Web Services Developer Pack Downloads page에서 Java WSDP 1.5를 다운로드, 설치한다.

  3. 예제 압축파일을 다운로드 받은 디렉토리를 변경하고, 다음과 같이 샘플 아카이브에 대한 JAR 파일의 압축을 푼다.
         jar xvf ttfeb2005sjsxp.jar
    
  4. 사용자의 classpathttfeb2005sjsxp.jarjsr173_api.jar를 포함하도록 설정한다. 이들은 Java WSDP 1.5 installation의 sjsxp/lib 디렉토리에 위치하고 있다.

  5. SJSXPInput를 컴파일하고 구동한다.

    다음의 각각의 XML 아이템과 유사한 엔트리가 나타날 것이다.
       Event Type (Code=11): DTD
       Without a Name
       With Text: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 
       Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-
       transitional.dtd">
      -----------------------------
    
  6. SJSXPOutput를 컴파일하고 구동한다. 결과는 XMLOutputFile라는 이름의 파일에 보내지며, 위의 결과 예제에 보여지는 요소들을 포함할 것이다.
Posted by 1010
반응형

//인터넷 XML 날씨 정보를 파싱 (DomParser.java)


import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class DomParser {

        private static Document xmlDoc = null;
        private static String XML_URL = "http://weather.unisys.com/forexml.cgi?seoul";
        private static String XML_NODE = "observation";
        private static String XML_CITY = "city";
        private static String XML_TIME = "time";
        private static String XML_SKIES = "skies";
        private static String XML_TEMP = "temp.C";

        public static void main(String[] args) {
                printXmlFromUrl(XML_URL);
        }

        private static void printXmlFromUrl(String urlString) {
                try {
                        URL url = new URL(urlString);

                        try {
                                URLConnection urlConnection = url.openConnection();
                                HttpURLConnection httpConnection = (HttpURLConnection)urlConnection;

                                int responseCode = httpConnection.getResponseCode();
                                if (responseCode == HttpURLConnection.HTTP_OK) {
                                        InputStream inputStream = httpConnection.getInputStream();

                                        // Parsing XML Document
                                        createDomParser(inputStream);
                                        String[] xmlData = getByTagName(XML_NODE);
                                        for (int i = 0; i < xmlData.length; i++) {
                                                System.out.println(xmlData[i]);
                                        }

                                        inputStream.close();
                                } else {
                                        System.out.println("HTTP Response is not \"HTTP Status-Code 200: OK.\"");
                                }
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                } catch (MalformedURLException e) { 
                        e.printStackTrace();
                }
        }

        private static void createDomParser(InputStream inputStream) {

                // Use factory to create a DOM document
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                factory.setIgnoringElementContentWhitespace(true);
                DocumentBuilder builder = null;

                try { // Get a DOM parser from the Factory
                        builder = factory.newDocumentBuilder();
                } catch (ParserConfigurationException e) {
                        e.printStackTrace();
                        return;
                }

                try { // Request the DOM parser to parse the file
                        xmlDoc = builder.parse(inputStream);
                } catch (SAXException e) {
                        e.printStackTrace();
                        return;
                } catch (IOException e) {
                        e.printStackTrace();
                        return;
                }
        }

        private static String[] getByTagName(String tagName) {

                if (!(xmlDoc == null)) {
                        NodeList nodes = xmlDoc.getElementsByTagName(tagName);
                        NamedNodeMap nodeMap = nodes.item(0).getAttributes();

                        String[] values = new String[4];
                        values[0] = nodeMap.getNamedItem(XML_CITY).getNodeValue();
                        values[1] = nodeMap.getNamedItem(XML_TIME).getNodeValue();
                        values[2] = nodeMap.getNamedItem(XML_SKIES).getNodeValue();
                        values[3] = nodeMap.getNamedItem(XML_TEMP).getNodeValue();
                        return values;
                }
                return null;
        }
}

Posted by 1010
반응형

XML Parser 함수들

함수

리턴 값

설명

xml_error_string(code)

string

제공된 오류 code와 결홥된 오류 메시지를 리턴한다.

xml_get_current_byte_index(parser)

integer

XML 파서를 위해 현제 바이트 인덱스를 리턴한다.

xml_get_current_column_number(parser)

integer

지정된 parser를 위해 현재 행 번호를 리턴한다.

xml_get_current_line_number(parser)

integer

지정된 parser를 위해 현재 줄 번호를 리턴한다.

xml_get_error_code(parser)

integer

마지막으로 발생한 xml,파서의 올에대한 오류 코드를 리턴한다.

xml_parse(parser, data, [is_final])

integer

지정된 data를 분석한다.

xml_parser_create([encoding_parameter])

integer

xml 파서를 작성한다.

xml_parser_free(parser)

Boolean

지정된 xml parser를 해제한다.

xml_parser_get_option(parser, option)

Mixed

지정된 parser에 대한 지정된 option의 값을 리턴한다.

xml_parser_set_option(parser, option, value)

integer

지정된 parser를 위해 option을 지정된 value로 설정한다.

xml_set_character_data_handler(parser, handler)

integer

문자 데이터 핸들러를 등록한다.

xml_set_default_handler(parser, handler)

integer

기본 핸들러를 등록한다.

xml_set_element_handler(parser, handler)

integer

시작과 끝 구성 요소 핸들러를 등록한다.

xml_set_external_entity_ref_handler(parser, handler)

integer

외부 엔티티 참조 핸들러를 등록한다.

xml_set_notation_decl_handler(parser, handler)

integer

표기법 선언 핸들러를 등록한다.

xml_set_processing_instruction_handler(parser, handler)

integer

처리 지시어 핸들러를 등록한다.

xml_set_unparsed_entity_decl_handler(parser, handler)

integer

분석되지 않은 엔티티 선어 핸들러를 등록한다.



[ xml_parser_create() ]

XML 파서 컨텍스트를 만든다.

int xml_parser_create(string [encoding_parameter]);

encoding_parameter : 파서가 사용할 문자 소스 암호화. 일단 설정된 소스 암호화는 나중에 변경할 수 없다. 가능한 값으로는 ISO-8859-1(default) , US-ASCII, UTF-8



[ xml_set_element_handler()]

"start()"와 “end()"ㅅ구성 요소 핸들러 함수들을 XML 파서에 등록한다.

int xml_set_element_handler( int parser, string startElementHandler , string endElementHandler);

parser : XML 파서의 핸들러. 시작과 끝 구성 요소 핸들러들이 등록되어있다.

startElementHandler : 시작 구성 요소 핸들러 함수의 이름. 만약 null이 지정되면 시작 구성 요소 핸들러가 등록되지 않은 것이다.

endElementHandler : 끝 구성 요소 핸들러 함수의 이름. 만약 null이 지정되면 끝 구성 요소 핸들러가 등록되지 않는다.


< satartElementHandler(int parser, string name, string attribs[]); >

parser : 이함수를 호출하고 있는 XML 파서에 대한 참조

name : 구성 요소의 이름

attribs() : 구성 요소의 속성들을 포함하고 있는 조합배열


< endElementHandler(int parser, string name); >

parser : 이 함수를 호출하고 있는 XML 파서로의 참조

name 구성요소 이름



[ xml_set_character_data_handler() ]

XML 파서에 문자 데이터 핸들러를 등록한다.

int xml_set_character_data_handler( int parser, string characterDataHandler);

parser : 문자 데이터 핸들러가 등록된 XML 파서를 위한 핸들

characterDataHandler : 문자 데이터 핸들러 함수의 이름. 만약 null이 지정되면 문자 데이터 핸들러가 등록되지 않는다.


< characterDataHandler( int parser, string data); >

parser : 이 함수를 호출 중인 XML 파서로의 참조

data : XML 문서에 제공되는 문자 데이터. 파서는 문자 데이터를 이TSms 그대로 리턴하며, 어떠한 공백 문자도 제거하지 않는다.



[ xml_parse() ]

XML 문서의 컨텐츠를 파서로 전달한다. 이 함수는 문서의 실제 분석을 수행한다(XML 문서에서 노드들을 만나면 등록된 적당한 핸들러들을 호출한다.).

이 함수는 XML 문서에 있는 다양한 노드 타입들에 대한 핸들러 함수들이 모두 파서에 등록된 후에 호출된다.

int xml_parse( int parser, string data, int [isFinal]);

parser : 제공된 데이터를 분석할 XML 파서의 핸들

data : XML 문서의 컨텐츠. XML 파일의 전체 컨텐츠는 한 번의 호출로 전달될 필요는 없다.

isFinal : 입력 데이터의 끝을 지정한다.

전달된 데이터의 분석이 가능하면 true를 리턴하고, 그렇지 않으면 false를 리턴한다. 실패이 경우 , 오류정보는 xml_get_error_code()와 xml_get_error_string()함수를 이용하여 발견 할 수 있다.



[ xml_get_error_code ]

XML 파서로부터 오류 코드를 리턴한다.

int xml_get_error_code( int parser);

parser : XML 파서으 핸들

분석에 실패하거나 유호한 XML파서가 아닐 경우 flase를 리턴한다.



[ xml_error_string ]

오류 코드에 따라 오류 메시지를 리턴한다.

string xml_get_error_code( int errorCode);

ErrorCode : xml_get_error_code() 함수가 리턴한 오류 코드





[ 예제 ]


<?
class RSSParser {
 var $feed_info = array();
 var $feed_articles = array();
 var $inchannel = FALSE;
 var $initem = FALSE;
 var $inimage = FALSE;
 var $current_item = array();
 var $current_el = FALSE;

 // 여는 태그 처리
 function startElement($parser, $name, $attrs)
 {
  $el = strtoupper($name);

  if ($el == 'RSS') {
   return;
  } else if ($el == 'CHANNEL') {
   $this->inchannel = TRUE;
  } else if ($el == 'ITEM') {
   $this->initem = TRUE;
  } else if ($el == 'IMAGE') {
   $this->inimage = TRUE;
  } else {
   $this->current_el = $el;
  }
 }

 // 닫는 태그 처리
 function endElement($parser, $name)
 {
  $el = strtoupper($name);

  if ($el == 'RSS') {
   return;
  } else if ($el == 'CHANNEL') {
   $this->inchannel = FALSE;
  } else if ($el == 'ITEM') {
   $this->feed_articles[] = $this->current_item;
   $this->current_item = array();
   $this->initem = FALSE;
  } else if ($el == 'IMAGE') {
   $this->inimage = FALSE;
  } else {
   $this->current_el = FALSE;
  }
 }

 // 태그 사이의 데이터 처리
 function characterData($parser, $data)
 {
  if ($this->initem) {
   if ($this->current_el) {
    $this->current_item[$this->current_el] .= $data;
   }
  } else if ($this->inimage) {
  } else if ($this->inchannel) {
   if ($this->current_el) {
    $this->feed_info[$this->current_el] .= $data;
   }
  }
 }
}

function parse_save_rss($document)
{
 // RSS 피드의 인코딩을 UTF-8에 맞춤
 if (preg_match('/<?xml.*encoding=[\'"](.*?)[\'"].*?>/m', $document, $m)) {
  $in_enc = strtoupper($m[1]);
  if ($in_enc != 'UTF-8') {
   $document = preg_replace('/(<?xml.*encoding=[\'"])(.*?)([\'"].*?>)/m', '$1UTF-8$3', $document);
   $document = iconv($in_enc, 'UTF-8', $document);
  }
 }

 // XML 및 RSS 분석기 생성
 $xml_parser = xml_parser_create('UTF-8');
 $rss_parser = new RSSParser();

 xml_set_object($xml_parser, $rss_parser);
 xml_set_element_handler($xml_parser, "startElement", "endElement");
 xml_set_character_data_handler($xml_parser, "characterData");

 if (!xml_parse($xml_parser, $document, true)) {
  printf("XML error: %s at line %d\n",
    xml_error_string(xml_get_error_code($xml_parser)),
    xml_get_current_line_number($xml_parser));
 } else {
  // 분석결과를 DB에 저장
  $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password') or die('Could not connect: '.mysql_error());
  mysql_select_db('my_database') or die('Could not select database');

  foreach ($rss_parser->feed_articles as $article) {
   $published = date('Y-m-d H:i:s', strtotime($article['PUBDATE']));

   $query = sprintf("INSERT INTO feed_articles (source, title, link, description, published) VALUES ('%s', '%s', '%s', '%s', '%s')",
       mysql_real_escape_string($rss_parser->feed_info['TITLE']),
       mysql_real_escape_string($article['TITLE']),
       mysql_real_escape_string($article['LINK']),
       mysql_real_escape_string($article['DESCRIPTION']),
       $published);
   if (mysql_query($query, $link)) echo $query."\n";
  }
 }

 xml_parser_free($xml_parser);
}

// 읽어올 피드 목록
$feed_urls = array(
  'http://blog.rss.naver.com/kickthebaby.xml',
  'http://srlog.egloos.com/index.xml',
  'http://feeds.feedburner.com/tapestrydilbert'
  );

foreach ($feed_urls as $url) {
 $handle = fopen($url, 'r');
 if ($handle) {
  $document = '';
  while (!feof($handle)) {
   $document .= fgets($handle, 4096);
  }
  echo $url."\n";
  // 읽어온 피드를 분석하여 DB에 저장
  parse_save_rss($document);
  fclose($handle);
 }
}
?>

Posted by 1010
반응형

Parser 와 DOM 기초

  • Parser
    • XML 문서를 읽고 해석 : well-formed, valid 검사
    • 응용 개발시 파서 사용 이유 : 세부적인 XML 문법으로부터 프로그램 격리
         XML 문서 --> [파서] -->인터페이스--> [응용 프로그램]
    • 파서가 메모리에 DOM 트리를 생성 : XML 문서트리와 일치
  • 표준 API
    • DOM : 객체 기반 (Object-based) Interface
      - 메모리 상주 트리 이용, 응용에서 간단히 사용, p.208
    • SAX : 이벤트 기반 (Event-driven) Interface
      - 파서가 간단, 응용프로그램은 복잡
  • DOM 개요
    • 문서내 객체(element)를 조작하기 위한 인터페이스(API)
      -
      DOM level 1 : ’98.10 W3C Recommendation
      - DOM level 2 : 2000.11 W3C Recommendation
      - DOM level 3 : 2001.8 W3C Working Draft
    • 문서 전체가 아닌 문서 일부분에 대한 접근 가능
    • 대상 문서 : XML1.0 또는 HTML4.0
  • DOM의 역할
    • 구조의 탐색 : 각 요소와 속성에 대한 탐색/질의가 가능
    • 문서 구조의 조작 : 문서 구조에서 요소, 속성의 추가/수정/삭제가 가능
    • 컨텐츠의 조작 : 문서 요소에서 text 등 컨텐츠의 탐색/추가/수정/삭제가 가능

Document 객체

  • DOMDocument 객체 생성 및 읽기
    • Msxml2.DOMDocument 객체
    • async 속성, load 메쏘드, xml 속성
    MSXML 파서 설치할 경우   MSXML 파서 설치안한 경우  
    <HTML>
    <HEAD>
    <Script language="Javascript">
    function xload0()
    {
        var xmldoc = new
            ActiveXObject("Msxml2.DOMDocument");
        xmldoc.async = false;    xmldoc.load("ex07a.xml");
        alert(xmldoc.xml);
    }
    </script>
    </HEAD>
    <BODY>
    <input type="button" value="XML 로드0"
        onClick="xload0()">
    </BODY>
    </HTML>
     
    111<HTML>
    <HEAD>
    <Script language="Javascript">
    function xload1()
    {
        xmldoc.async = false;
        xmldoc.load("ex07a.xml");

        alert(xmldoc.xml);
    }
    </script>
    </HEAD>
    <BODY>
    <input type="button" value="XML 로드1"
        onClick="xload1()">
    <xml id="xmldoc"></xml>
    </BODY>
    </HTML>
    VBScript 의 경우
    <Script language="VbScript">
      Dim xmldoc
      Set xmldoc = CreateObject("Msxml2.DOMDocument")
      xmldoc.async = False;
      xmldoc.load("ex07a.xml");
      MsgBox xmldoc.xml
    </Script>
  • 신규 문서 작성 : loadXML 메쏘드
     xmldoc.async = false;
     xmldoc.loadXML( "<book><title>XML 입문</title><author>일지매</author></book>");
     alert(xmldoc.xml);
     
     xmldoc.async = false;
     xmldoc.loadXML( "<book> <title> XML 입문 </title> <author> 일지매 </author> </book>");
     alert(xmldoc.xml);
     
  • 공백의 처리 : preserveWhiteSpace 속성
     xmldoc.async = false;
     xmldoc.preserveWhiteSpace = true;
     xmldoc.loadXML( "<book> <title> XML 입문 </title> <author> 일지매 </author> </book>");
     alert(xmldoc.xml);
     
     xmldoc.async = false;
     xmldoc.preserveWhiteSpace = true;
     xmldoc.load("ex07a.xml");
     alert(xmldoc.xml);
     
  • XML 문서의 저장 : save 메쏘드
  • 에러 처리 : parseError, parseError.line, parseError.linepos, parseError.reason
     xmldoc.async = false;
     xmldoc.loadXML( "<book> <title> XML 입문 </title> <author> 일지매 </authors> </book>");
     alert(xmldoc.xml);
     
     xmldoc.async = false;
     xmldoc.loadXML( "<book> <title> XML 입문 </title> <author> 일지매 </authors> </book>");
     if (xmldoc.parseError)
        alert("에러 위치 : " + xmldoc.parseError.line + "번째 라인 " + xmldoc.parseError.linepos 
                  + "번째 문자\n\n에러 이유 : " + xmldoc.parseError.reason);
     else
    alert(xmldoc.xml);
     
  • 루트 노드 찾기 : documentElement 속성
     xmldoc.async = false;
     xmldoc.load("ex07a.xml");
     var xmlroot = xmldoc.documentElement;
     alert(xmlroot.nodeName);
     
     xmldoc.async = false;
     xmldoc.loadXML( "<book> <title> XML 입문 </title> <author> 일지매 </author> </book>");

     var xmlroot = xmldoc.documentElement;
     alert(xmlroot.nodeName);

     
  • 임의의 노드 찾기 : getElementsByTagName("tagName")
  • 노드의 추가 메쏘드 : 뒤에 설명
    • createElement(name), createTextNode(data), createAttribute(name), createComment(data), createProcessingInstruction(target,data), createCDATASection(data), createEntityReference(name)

Node 객체

  • nodeName, nodeType, nodeValue, attributes, text 속성
    • nodeType = 1(element), 2(attribute), 3(text) , 4(CDATA), ...  : 표7.1 [p.215]
     xmldoc.load("ex07a.xml");
     var xmlroot = xmldoc.documentElement;
     alert('nodeName: '+xmlroot.nodeName+'\nnodeType: '+xmlroot.nodeType+
           '\nnodeValue: '+xmlroot.nodeValue+'\nattributes: '+xmlroot.attributes.length);
     alert(xmlroot.text);
     
  • Node의 운행(Traversal) 관련 속성
    • 관련속성
                                  -- previousSibling 
      ...  parentNode  -- **현재노드**    --  childNodes [ firstChild, … , lastChild ]
                                  -- nextSibling 
    • hasChildNodes() 메쏘드
  • NodeList 객체
    • length 속성, item(번호) 메쏘드
     xmldoc.load("ex07a.xml");
     var xmlroot = xmldoc.documentElement;
     if (xmlroot.hasChildNodes) {
         alert(xmlroot.childNodes.length);
         var curr = xmlroot.firstChild;
         alert(curr.xml);
         alert(curr.nodeName + curr.nodeType
          +curr.nodeValue+curr.attributes.length);
     }
     else alert('No Child');
     
     xmldoc.load("ex07a.xml");
     var xmlroot = xmldoc.documentElement;
     var curr = xmlroot.firstChild.nextSibling;
     alert(curr.xml);
     curr = curr.childNodes.item(2);
     alert(curr.xml);
     curr = curr.previousSibling;
     alert(curr.text);
     alert(curr.nodeName + curr.nodeType
          +curr.nodeValue+curr.attributes.length);
     
  • NamedNodeMap 객체 
    • getNamedItem("속성명"), setNamedItem(), removeNamedItem() 메쏘드
  • Attribute 객체 
    • name, value, specified 속성
     xmldoc.load("ex07a.xml");
     var attrs = xmlroot.firstChild.attributes;
     var attr0 = attrs.getNamedItem("InStock");
     alert(attr0.name + attr0.value + attr0.specified); 
  • 노드의 추가/삭제/수정 메쏘드 : 뒤에 설명
    • appendChild(child), insertBefore(child,before), removeChild(child),
      replaceChild(child,toReplace), cloneNode(deep)

임의 노드의 검색

  • 그 이름으로 검색
    • 노드리스트 = 문서.getElementsByTagName("tagName");
     xmldoc.load("ex07a.xml");
     var nlist =
       xmldoc.
    getElementsByTagName("book");
     for (i=0; i<nlist.length; i++)
            alert(nlist.item(i).xml);
     
     xmldoc.load("ex07a.xml");
     var nlist =
        xmldoc.
    getElementsByTagName("title");
     for (i=0; i<nlist.length; i++)
            alert(nlist.item(i).xml);
     
  • 패턴으로 검색
    • 노드리스트 = 노드.selectNode("query");
    • 노드 = 노드.selectSingleNode("query");
     xmldoc.load("ex07a.xml");
     var xroot = xmldoc.documentElement;
     var node1 = xroot.selectSingleNode("title");
     alert(node1.text);
     var tlist = xroot.selectNodes('//title');
     var alist = xroot.selectNodes('//author');
     for (i=0; i<alist.length; i++)  
        alert('['+i+'] '+alist.item(i).text+', '
               +tlist.item(i).text);

     
     xmldoc.load("ex07a.xml");
     var xroot = xmldoc.documentElement;
     var node1 = xroot.
        selectSingleNode
    ('//book[@InStock=0]');
     alert(node1.xml+'\n=> 재고가 없습니다.');
     var tlist = xroot.
        selectNodes
    ('//book[@InStock!=0]/title');
     for (i=0; i<tlist.length; i++)
        alert(tlist.item(i).text+'\n=>재고 있음.');

     

 

펌 -  http://mm.sookmyung.ac.kr/~sblim/lec/xml-int02/

MSDN - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/dom_reference.asp

Posted by 1010
반응형
 

Xerces-J contains many useful samples to help you get up-and-running with writing XML applications. Many of the sample programs are even useful as standalone programs to help in testing the validity of XML documents and/or debugging applications.

The samples are organized either by API or by programming area in the following categories:

Posted by 1010
반응형
he XML parser world is a dynamic one. As standards change, the parsers change as well--XML parsers are becoming more sophisticated. For most programming projects, the parser, at minimum, must support DOM Level 2, SAX 2, XSLT, and Namespaces. All the parsers discussed here provide these capabilities; however, there are distinct differences in performance, reliability, and conformance to standards. In this article, I'll compare the latest parsers from Sun, Oracle, and the Apache Software Foundation.

Apache parser
The Apache parser version 1.2.3 (commonly known as Xerces) is an open-source effort based on IBM's XML4J parser. Xerces has full support for the W3C Document Object Model (DOM) Level 1 and the Simple API for XML (SAX) 1.0 and 2.0; however it currently has only limited support for XML Schemas, DOM Level 2 (version 1). Add the xerces.jar file to your CLASSPATH to use the parser. You can use Xalan, also available from Apache's Web site, for XSLT processing. You can configure both the DOM and SAX parsers. Xerces uses the SAX2 method getFeature() and setFeature() to query and set various parser features. For example, to create a validating DOM parser instance, you would write:

DOMParser domp = new DOMParser();
   try {
      domp.setFeature ("http://xml.org/dom/features/validation", true);
   } catch (SAXExcepton ex) {
      System.out.println(ex);
   }
Other modifiable features include support for Schemas and namespaces.

The following example shows a minimal program that counts the number of <servlet> tags in an XML file using the DOM. The second import line specifically refers to the Xerces parser. The main method creates a new DOMParser instance and then invokes its parse() method. If the parse operation succeeds, you can retrieve a Document object through which you can access and manipulate the DOM tree using standard DOM API calls. This simple example retrieves the "servlet" nodes and prints out the number of nodes retrieved.

import org.w3c.dom.*;
import org.apache.xerces.parsers.DOMParser;

public class DOM
{
    public static void main(String[] args) 
    {

        try {
            DOMParser parser = new DOMParser();
            parser.parse(args[0]);
            Document doc = parser.getDocument();

            NodeList nodes = doc.getElementsByTagName("servlet");
            System.out.println("There are " + nodes.getLength() + 
               " elements."); } catch (Exception ex) { System.out.println(ex); } } }

You can use SAX to accomplish the same task. SAX is event-oriented. In the following example, inherits from DefaultHandler, which has default implementations for all the SAX event handlers, and overrides two methods: startElement() and endDocument(). The parser calls the startElement() method each time it encounters a new element in the XML file. In the overridden startElement method, the code checks for the "servlet" tag, and increments the tagCounter counter variable.. When the parser reaches the end of the XML file, it calls the endDocument() method. The code prints out the counter variable at that point. Set the ContentHandler and the ErrorHandler properties of the the SAXParser() instance in the main() method , and then use the parse() method to start the actual parsing.

import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.xerces.parsers.SAXParser;

public class SAX extends DefaultHandler
{    
      int tagCount = 0;

      public void startElement(String uri, String localName,
         String rawName, Attributes attributes)
      {
            if (rawName.equals("servlet")) {
               tagCount++;
            }
      }

      public void endDocument()
      {
            System.out.println("There are " + tagCount +
                " <servlet> elements.");
      }

      public static void main(String[] args)
      {
            try {
                  SAX SAXHandler = new SAX();

                  SAXParser parser = new SAXParser();
                  parser.setContentHandler(SAXHandler);
                  parser.setErrorHandler(SAXHandler);
                  parser.parse(args[0]);
            }
                  catch (Exception ex) {
                        System.out.println(ex);
                  }
      }
}

With Xerces installed and your CLASSPATH set, you can compile and run the above programs as follows:

javac DOM.java
javac SAX.java
C:\xml\code>java DOM web.xml
There are 6 <servlet> elements.
C:\xml\code>java SAX web.xml
There are 6 <servlet> elements.
Posted by 1010
반응형
============= common.jsp =============================

<%@ page contentType="text/html;charset=EUC-KR" %>
<% request.setCharacterEncoding("euc-kr"); %>
<%@ page import="java.util.*" %>
<%@ page import="java.net.*" %>
<%@ page import="javax.xml.parsers.*" %>
<%@ page import="org.w3c.dom.*" %>


<%!

 final String G_ROOT_URL="http://locahost:6973/test.cgi?";

 final String strVal(String str){
  if(str == null) str = "";
  return str.trim();
 }

 class T_DOC{
  String id;
  String sim;
  HashMap<String,String> hm_item=new HashMap<String,String>();
 }


 class SrchInfo{


  StringBuffer m_URL=new StringBuffer();
 
  SrchInfo(){
   m_URL.append(G_ROOT_URL);
  }
 
  public void SetQRY(String p_name,String p_value){
   m_URL.append(p_name + "=" + p_value + "&");
  }

  //  헤더 정보 변수
  String m_section_name;
  String m_usrspec;
  String m_idxname;
  String m_qryflag;
  String m_srtflag;
  String m_totcnt;
  String m_maxcnt;
  String m_outcnt;
  String m_pagenum;
 
  // 결과 정보
  ArrayList<T_DOC> m_DOCS=new ArrayList<T_DOC>();


  private DocumentBuilderFactory docBuilderFactory;

  private DocumentBuilder docBuilder;

  private Document doc;
  private NodeList nodeDOC;
 
  public void GetData(){

   try{
   
 // DocumentBuilderFactory 의 객체 생성
 DocumentBuilderFactory docBuilderFactory=DocumentBuilderFactory.newInstance();
 // factory로부터 DocumentBuilder 를 얻어온다.
 DocumentBuilder docBuilder=docBuilderFactory.newDocumentBuilder();

   // XML 문서로부터 DOM 객체를 만들어서 문서(Document) 로 반환 받는다.
   //System.out.println(p_xmlfile);
   
   Document doc=docBuilder.parse(m_URL.toString());
   
   //메타 정보 추출
   nodeDOC=doc.getElementsByTagName("section");
   
  m_section_name=nodeDOC.item(0).getAttributes().getNamedItem("name").getNodeValue();
 
  m_usrspec=nodeDOC.item(0).getChildNodes().item(1).getFirstChild().getNodeValue();
  m_idxname=nodeDOC.item(0).getChildNodes().item(3).getFirstChild().getNodeValue();
  m_qryflag=nodeDOC.item(0).getChildNodes().item(5).getFirstChild().getNodeValue();
  m_srtflag=nodeDOC.item(0).getChildNodes().item(7).getFirstChild().getNodeValue();
  m_totcnt=nodeDOC.item(0).getChildNodes().item(9).getFirstChild().getNodeValue();
  m_maxcnt=nodeDOC.item(0).getChildNodes().item(11).getFirstChild().getNodeValue();
  m_outcnt=nodeDOC.item(0).getChildNodes().item(13).getFirstChild().getNodeValue();
m_pagenum=nodeDOC.item(0).getChildNodes().item(15).getFirstChild().getNodeValue();
   
   
   int count=Integer.parseInt(m_outcnt);
   
   for ( int i=0 , idx=19; i < count ; i++ , idx+=2 ){
   
    T_DOC tmp_doc=new T_DOC();
   
tmp_doc.id=nodeDOC.item(0).getChildNodes().item(idx).getAttributes().getNamedItem("id").getNodeValue();
tmp_doc.sim=nodeDOC.item(0).getChildNodes().item(idx).getAttributes().getNamedItem("sim").getNodeValue();
 
    int child_cnt=nodeDOC.item(0).getChildNodes().item(idx).getChildNodes().getLength();
     
    for ( int j = 1 ; j < child_cnt ; j+=2 ) {
     
 String tag=nodeDOC.item(0).getChildNodes().item(idx).getChildNodes().item(j).getAttributes().getNamedItem("name").getNodeValue();
 String value=nodeDOC.item(0).getChildNodes().item(idx).getChildNodes().item(j).getFirstChild().getNodeValue();
     tmp_doc.hm_item.put(tag,value);
    }
   
    m_DOCS.add(tmp_doc);
   }
   
    }catch(java.lang.Exception e) {

               System.err.println("==GetData()]"+ e.toString());
               e.printStackTrace(System.out);
              // System.exit(-1);
       }
  }// end of  GetHeader
 
  public void GetResults(){

  }

}//end of class

%>


==================== index.jsp ===========================================

실제 사용 샘플 페이지
 
<%--   xml parse fs 2008 07 --%>
<%@ page contentType="text/html;charset=EUC-KR" %>
<% request.setCharacterEncoding("euc-kr"); %>
<%@ include file="common.jsp" %>

<%
 SrchInfo OB_SrchInfo=new SrchInfo();

 OB_SrchInfo.SetQRY("w","test");

 String qry=strVal(request.getParameter("qry"));
 
 if( qry.length() == 0 ) qry="*";


 OB_SrchInfo.SetQRY("q",URLEncoder.encode(qry));

 //  xml 파서 시작
 OB_SrchInfo.GetData();

 out.println("<xmp> "  + OB_SrchInfo.m_URL + "</xmp>" );

%>

 <HEAD>

 <TITLE>XML JAVA 파서 샘플 페이지</TITLE>

 </HEAD>

 <BODY>
 <P>
 <table>
 <form name=form action=index.jsp method=get>
  검색어:<input type=text name=qry value=<%= qry %>>
  <input type=submit value="검색">
 </form>

 </table>
 <검색 결과 헤더 정보> : <br>
  &nbsp;&nbsp;- 전체건수: <%= OB_SrchInfo.m_totcnt %> <br>
  &nbsp;&nbsp;- 요청건수(outmax값): <%= OB_SrchInfo.m_maxcnt %> <br>
  &nbsp;&nbsp;- 출력건수: <%= OB_SrchInfo.m_outcnt %> <br>
  &nbsp;&nbsp;- 출력페이지번호: <%= OB_SrchInfo.m_pagenum %> <br>

 <p>
 <검색 결과 데이터> :
 <p>

<%
 
 for(int i=0; i < OB_SrchInfo.m_DOCS.size() ; i++){
 
  T_DOC RESULT=OB_SrchInfo.m_DOCS.get(i);
 
  out.println( "DOC ID : " +  RESULT.id  + "<br>");
  out.println( "DOC SIM : " + RESULT.sim + "<br>");
  out.println( "제목 : " + RESULT.hm_item.get("TITLE=") + "<br>");
  out.println( "내용 : " + RESULT.hm_item.get("ARTICLE=") + "<p>");

 }
%>


실제 활용예 소스는 아니지만 좀 아는 사람이라면
실무에 패키지해서 유용하게 사용할수도 있을것이다~~
2008 07 fs

Posted by 1010
반응형

<html>
<head>
<script type="text/javascript">
function parseXML()
{
text="<note>";
text=text+"<to>Tove</to>";
text=text+"<from>Jani</from>";
text=text+"<heading>Reminder</heading>";
text=text+"<body>Don't forget me this weekend!</body>";
text=text+"</note>";
try //Internet Explorer
  {
  xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
  xmlDoc.async="false";
  xmlDoc.loadXML(text);
  }
catch(e)
  {
  try //Firefox, Mozilla, Opera, etc.
  {
  parser=new DOMParser();
  xmlDoc=parser.parseFromString(text,"text/xml");
  }
  catch(e)
  {
  alert(e.message);
  return;
  }
}
document.getElementById("to").innerHTML=xmlDoc.getElementsByTagName("to")[0].childNodes[0].nodeValue;
document.getElementById("from").innerHTML=xmlDoc.getElementsByTagName("from")[0].childNodes[0].nodeValue;
document.getElementById("message").innerHTML=xmlDoc.getElementsByTagName("body")[0].childNodes[0].nodeValue;
}
</script>
</head>

<body onload="parseXML()">
<h1>W3Schools Internal Note</h1>
<p><b>To:</b> <span id="to"></span><br />
<b>From:</b> <span id="from"></span><br />
<b>Message:</b> <span id="message"></span>
</p>
</body>
</html>


Posted by 1010
반응형

<html>
<head>
<script type="text/javascript">
function parseXML()
{
try //Internet Explorer
  {
  xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
  }
catch(e)
  {
  try //Firefox, Mozilla, Opera, etc.
    {
    xmlDoc=document.implementation.createDocument("","",null);
    }
  catch(e)
    {
    alert(e.message);
    return;
    }
  }
xmlDoc.async=false;
xmlDoc.load("note.xml");
document.getElementById("to").innerHTML=xmlDoc.getElementsByTagName("to")[0].childNodes[0].nodeValue;
document.getElementById("from").innerHTML=xmlDoc.getElementsByTagName("from")[0].childNodes[0].nodeValue;
document.getElementById("message").innerHTML=xmlDoc.getElementsByTagName("body")[0].childNodes[0].nodeValue;
}
</script>
</head>

<body onload="parseXML()">
<h1>W3Schools Internal Note</h1>
<p><b>To:</b> <span id="to"></span><br />
<b>From:</b> <span id="from"></span><br />
<b>Message:</b> <span id="message"></span>
</p>
</body>
</html>


Posted by 1010
반응형

SOAP 기반 XML 웹서비스에 아무리 주의를 기울이고 있다 하더라도 SOAP과 호환되지 않는 수많은 유용한 서비스와 컨텐츠가 있다는 사실을 잊기 쉽다. 이번 테크팁에서는 웹 티어로부터 기존의 웹 리소스들을 사용하기 위해 서블렛을 어떻게 사용하는 지 보여준다. 이 경우에 기존 웹 서비스란 비표준 기반 XML 서비스를 말한다.

기존 리소스 호환

적어도 지금까지는 웹의 대부분의 컨텐츠를 표준 기반 웹 서비스 형식에서 사용할 수 없었다. HTML 페이지, 텍스트 파일, PDF나 워드 프로세서 같은 문서 파일, ftp 사이트 안의 파일들과 이미지들 형식에서 많은 정적 컨텐츠가 존재한다. 어떤 서비스들은 HTTP POSTGET 요구에 따라 활발하게 XML을 생산하기도 하며, RSS feeds 같은 다른 서비스들은 정적인 URL을 가지고 있으나, 그들의 데이터가 동적이어서 보통 직접 사용자에 의해 사용되기 보다는 프로그램에 의해 사용되기 때문에 서비스의 역할을 한다.

엔터프라이즈Java 테크놀로지는 조직 내 인트라넷과 일반 인터넷에서 모두 기존 리소스들과 훌륭히 호환된다. 엔터프라이즈Java 테크놀로지는 새로운 시스템에 기존 정보 자산을 통합하기 위해 어느 티어에서나 사용될 수 있다. SOAP 기반 웹 서비스들이 기존 리소스들을 통합하는 새로운 시스템을 생성하는 것을 기다릴 필요가 없는 것이다.

다음은 통합적인 애플리케이션을 제공하기 위해 엔터프라이즈 Java 서버가 다양한 기존 웹 리소스들을 통합하는 구성도이다.

업무에서의 검색엔진

The National Library of Medicine은 미국방부의 건강 관련 기관 중 하나이다. PubMed*는 NLM의 서비스 중 하나로, 생체의학분야의 출판물 요약본 DB를 검색 가능하도록 제공한다. PubMed의 검색엔진은 Entrez로 불리며, 주소창에pubmed라고 입력하거나 http://www.ncbi.nlm.nih.gov/entrez/query.fcgi 로 들어가서 이 Entrez를 사용해볼 수 있다.

다음의 그림은 PubMed 사이트에서"neanderthal dna" 를 검색한 결과 중 일부이다.

PubMed는 또한 e-uilities라고 불리는 서비스를 제공한다. 이 서비스는 검색엔진에 프로그램적 인터베이스를 제공하는데, 클라이언트로부터 HTTP GET 요구를 받아 검색 결과를 나타내는 XML을 리턴할 수 있다.

이 테크팁을 수행하는 샘플 코드는 e-utilities 중 두가지에 접근하는 서블렛이다.

  • esearch. 검색을 실행하고 ID 리스트를 리턴한다.
  • efetch. 다양한 형식으로 요청된 문서를 불러온다.

esearch 이나 efetch로부터 리턴된 XML을 브라우저에 표시할 수 있게끔 XSLT스타일시트에 의해 변환되도록 지정하는 옵션도 있다. 서블렛은 클라이언트가 어떤 매개변수를 제공하는가에 따라 적절한 스타일시트를 사용할 것이다.

서블렛 개요

Jul2004Servlet라 불리는 샘플코드 서블렛은 새로운 기능을 제공하기 위해 기존 웹 서비스인 esearchefetch를 사용한다. 서블렛은 입력 매개변수를 GET URLs로 변환하여, 분석하고 표시하기 위해 데이터를 검색하는데 이를 사용한다. 서블렛은 먼저 검색을 실행하기 위해 esearch를 호출하고, 그 후 결과를 검색하기 위해 efetch를 호출한다.

다음은 서블렛이 결과를 도출하기 위해 진행되는 과정을 보여주는 순서도이다. 서블렛이 결과를 도출하기 위해 다양한 HTTP GETs의 결과를 사용하였다는 것에 주의하기 바란다.

  1. 서블렛은 유저 형식로부터 POST 매개변수를 수신하고 esearch가 요청하는 매개 변수로 HTTP GET URL를 구축한다.
  2. 서블렛은 URL로 HTTP GET을 실행한다. esearch e-utility는 서버용 결과 집합을 식별하는 데이터를 가진 XML을 리턴한다.
  3. 서블렛은 esearch로부터 리턴된 XML을 파싱하고, WebEnvQueryKey를 검색하기 위해 DOM API를 호출한다. 그 후 이 값들을 이용해 URL을 구축하여 데이터를 얻는다.
  4. 서블렛은 이번엔 efetch에 또다른 HTTP GET를 실행시킨다. 이는 결과 집합을 식별하고 원래의 요청에서 지정된 매개변수들을 형식화한다.
  5. 서블렛은 efetch로부터 요청된 문서 데이터를 수신하여 데이터를 XSL로 임의 변환하고 브라우저에 결과를 표시한다.

데이터베이스 검색

Entrez 서버에서 문서정보를 검색하는 첫번째 단계는 애플리케이션의 index.html에 있는 입력폼의 몇가지 매개 변수에 대해 esearch를 실행시키는 것이다. esearch는 Entrez 서버를 조회하여 조회 결과에 부합되는 데이터를 리턴한다. HTTP GET 쿼리 문자열이 "usehistory=y"라는 매개변수를 포함하고 있다면, Entrez 서버는 WebEnv 문자열과 QueryKey 라는 두가지 데이터 아이템을 추가하여 리턴한다. WebEnv 문자열은 Entrez 서버 안의 세션에서 유저 상태(과거에 있었던 쿼리와 그 결과 집합을 포함)에 대한 독자적인 식별자이며, QueryKey는 세션 안의 특정 쿼리를 식별하는 작은 정수이다. 종합하자면, WebEnvQueryKey를 합하면 서버에서의 쿼리 결과를 나타내게 된다. 서블렛은 애플리케이션의 index.html 페이지에 있는 입력폼로부터 몇 가지 매개 변수를 수신한다. 다음은 입력폼 샘플이다.

서블렛은 애플리케이션의 index.html 페이지에 있는 입력폼로부터 몇 가지 매개 변수를 수신한다.

다음은 입력폼 샘플이다.

서블렛 코드는URL을 구축하기 위해 다음과 같이POST매개 변수를 사용한다.

   AbstractMap paramMap = new TreeMap();
   
   res.setContentType("text/html");
   OutputStream os = res.getOutputStream();
   
   // Get parameters
   String query = req.getParameter("query");
   
   // Execute esearch
   // db=PubMed: search PubMed database
   // usehistory=y: return key to server-side result set
   // term=$query: search for "$term" in PubMed
   paramMap.put("db", "PubMed");
   paramMap.put("usehistory", "y");
   paramMap.put("term", query);
   
   // Create the URL and get its content
   String surl = buildUrl(BASEURL_ESEARCH, paramMap);
   InputStream is = getContent(surl);

여기서 사용된 buildUrl메서드는 기본 URL을 받아서 맵 상의 각각의 키와 컨텐츠 쌍에 대해 key=content라는 키를 생성함으로써 HTTP GET URL을 만든다. 컨텐츠는 URL로 인코딩 되어있으며 매개 변수는 스트링"&"와 결합하여 HTTP GET URL을 생성한다. 예를 들어 형식 쿼리가 "neanderthal DNA"이면 쿼리 문자열은 다음과 같다.

   db=PubMed&term=neanderthal+dna&usehistory=y

getContent 메서드는 요청된 URL에게 간단히 HttpUrlConnection을 개방하고, 결과 컨텐츠에 대해 다음과 같이 InputStream을 리턴한다.

   protected InputStream getContent(String surl)
      throws ServletException {
      Object content = null;

      try {
         // Connect to URL
         URL url = new URL(surl);
         HttpURLConnection conn =
            (HttpURLConnection)url.openConnection();
         conn.connect();

         // Get content as stream
         content = conn.getContent();
      } catch (Exception e) {
         throw new ServletException(e);
      }
      return (InputStream)content;
   }

esearch 요청에 대한 입력 스트림은 다음과 같은 XML 문서를 포함한다.

   <?xml version="1.0"?>
   <!DOCTYPE eSearchResult PUBLIC
     "-//NLM//DTD eSearchResult, 11 May 2002//EN"
     "http://www.ncbi.nlm.nih.gov/entrez/query/DTD/eSearch_020511.dtd">
   <eSearchResult>
      <Count>19</Count>
      <RetMax>19</RetMax>
      <RetStart>0</RetStart>
      <QueryKey>1</QueryKey>

      <WebEnv>0ed8yFoq_CFyEEP6hW9aZ9UoTCVrrPm2w343S9MRNaT9MQmwbnjI
      </WebEnv>
      <!-- additional data removed for brevity -->
   </eSearchResult>

서블렛은 이 XML 문서에서 QueryKeyWebEnv 요소의 컨텐츠를 추출해야하며, 이 컨텐츠를 efetch 후속 호출에 포함시켜야한다. 그러면 디스플레이를 위한 문서 데이터를 리턴하게 될 것이다.

결과 도출

efetch 결과가 작기 때문에 in-memory DOM 트리로 파싱이 가능하다. esearch로 리턴된 스트링을 파싱하는 서블렛은, 파싱하는 동안 Document오브젝트를 메모리로 가져오기 위해 DocumentBuilder를 사용한다.

   // Create DOM parser and parse search result
   DocumentBuilderFactory dbf =
   DocumentBuilderFactory.newInstance();
   DocumentBuilder db = dbf.newDocumentBuilder();
   Document esearchDoc = db.parse(is);
   
   // Get WebEnv, Count, and QueryKey from result
   // WebEnv - result key
   // QueryKey - history index
   // Count - result set length
   String webenv = getElementString(esearchDoc, "WebEnv");
   String count = getElementString(esearchDoc, "Count");
   String querykey = getElementString(esearchDoc, "QueryKey");

getElementString메서드는 주어진 이름(파일명)의 노드를 찾고 그 노드의 첫번째 Text 하위노드를 리턴하는 간단하고 편리한 기능을 한다. 서블렛은 파싱된 DOM 문서로부터 WebEnvQueryKey 를 추출한다.

이 때에, 서블렛은 서버에서 대기하는 결과 집합을 포함하고 있다. 다음 단계는 efetch를 사용하여 데이터를 검색하고 포맷하는 것이다.

Fetch 매개변수 지정

Efetch에서는 esearch의 결과를 식별하기 위해 단지 몇가지의 매개변수만을 필요로한다.

  • db. 데이터베이스 식별("PubMed")
  • WebEnv. 세션 식별
  • query_key. 세션 안의 쿼리 식별

추가 매개 변수들은 사이즈를 제한하거나, 리턴되는 데이터의 포맷 제어하는 역할을 한다.

  • retstartretmaxefetch 가 결과 중 일부 집합을 리턴하도록 명령한다. 이 때 이 결과치는 retstart에서 시작하고 retmax 레코드보다 작은 값을 리턴한다. 이 매개 변수들이 없으면 efetch는 종종 몇만 메가바이트가 되곤 하는 전체 결과를 리턴하고 만다.
  • retmode는 XML, HTML, text, ASN.1 중 어떤 형식으로 데이터를 생성할 것인지 지정한다. 기본값은 ASN.1, PubMed 의 네이티브 스토리지, 그리고 교환 포맷이다.
  • rettype은 각 레코드에서 어떤 것을 리턴할 지 명령한다. efetch은 기본값으로 abstracts을 리턴한다.

서블렛은 esearch에서와 같이 요청된 매개변수들의 Map을 생성한다. 서블렛이 esearch에서 검색한 WebEnvQueryKey스트링을 사용하고, 또한 원래 형식에서 수신한 몇가지 매개변수들을 포함한다. getParameter메서드는, 매개변수가 설정되지 않았을 때 기본값으로 대체하는 요청으로부터 간단히 매개변수를 얻는다.

   paramMap = new TreeMap();
   paramMap.put("WebEnv", webenv);
   paramMap.put("query_key", querykey);
   paramMap.put("db", "PubMed");
   paramMap.put("retstart", getParameter(req, "start", "0"));
   paramMap.put("retmax", getParameter(req, "max", "20"));
   paramMap.put("retmode",
   retmode = getParameter(req, "retmode", "xml"));
   paramMap.put("rettype", getParameter(
           req, "rettype", "abstract"));
   
   // Create URL and get its content
   surl = buildUrl(BASEURL_EFETCH, paramMap);
   is = getContent(surl);

서블렛은 요청된URL을 구축하기위해 맵을 사용하며, 요청 결과로 InputStream 을 얻기 위해 getContent 을 사용한다.

문서 변환

요청된 데이터 형식이 XML이 아니거나 유효한 스타일시트가 없다면 서블렛은 efetch로 리턴된 데이터를 복사하여 브라우저에 표시한다. 이 기능은 e-utilities로 직접 실험할 때 유용하다.

데이터가 XML형식이고 비어있지 않은 유효한 스타일시트가 있다면 서블렛은 이 스타일시트를 데이터에 적용하여 결과를 브라우저에 리턴한다. 브라우저에 리턴엔 XML은 각 레코드에 대해 약간씩의 데이터를 포함하고 있다. 다음은 리턴된 데이터를 발췌한 것이다.

    <?xml version="1.0"?>
    <!DOCTYPE PubmedArticleSet PUBLIC "...">
    <PubmedArticleSet>
     <PubmedArticle>
      <MedlineCitation Owner="NLM" Status="In-Process">
       <!-- ... -->
       <Article>
       <!-- ... -->
        <ArticleTitle>The thermal history of human fossils
        and the likelihood of successful DNA amplification.
        </ArticleTitle>
       <!-- ... -->

이 데이터는 결과를 도출하기 위해 수행되는 스타일시트의 컨텐츠이다.

적용할 스타일시트를 지정하는 데에는 두가지 방법이 있다. 첫번째로는, 사용자형식에는 라디오 버튼으로 되어있는 "isFile" 사용자 형식인제, 변환하기 위해 어떤 시트를 사용할 것인지 지정한다. IsFile이 1이면 매개변수 stylesheet는 웹애플리케이션 아카이브(WAR file)의 스타일시트 이름을 포함하게된다. IsFile이 0이면 매개변수 sstext는 사용자가 형식 안의 TEXTAREA에 넣는 스타일시트를 사용한다. 서식화된 레코드를 보고자 할 때 이 기능을 사용하면 된다. 또한 텍스트 에디터로부터 바로 형식으로 XSL을 카피하여 새로운 레포트를 생성할 때도 사용할 수 있다.

변환을 수행하는 코드는 다음을 얻는다.

  • efetch 결과로부터 읽어드린 입력 스트림
  • 서블렛 결과에 작성되는 결과 스트림
  • 매개 변수 isFile
  • 스타일시트의 이름이나 스타일시트 안의 텍스트 자체를 포함하는 스트링

이 메서드는 스타일시트로부터 Transformer 오브젝트를 구축한 후 소스와 수신자로서 입력과 출력 스트림을 전달하는 Transformer의 transform메서드를 호출한다.

   // Create XSLT transformer for output.
   TransformerFactory tf = TransformerFactory.newInstance();
   Transformer t = null;
   
   // Use identity transform if no transformer was specified
   if (stylesheet == null || stylesheet.equals("")) {
      t = tf.newTransformer();
   } else {
      StreamSource xslsource = null;

      if (isFile) {
         // Read XSL stylesheet from app archive and wrap it as
         // a StreamSource. Then use it to construct 
         // a transformer.
         InputStream xslstream = _config.getServletContext().
            getResourceAsStream(stylesheet);
         xslsource = new StreamSource(xslstream);
      } else {
         // Read XSL stylesheet from string
         xslsource = new StreamSource(
                 new StringReader(stylesheet));
      }
      t = tf.newTransformer(xslsource);
   }
   
   // Do transform from input (e-utilities result) to
   // output (servlet writer)
   StreamSource ss = new StreamSource(is);
   StreamResult sr = new StreamResult(os);
   t.transform(ss, sr);

변환이 완료되면 출력 스트림에 결과 HTML을 작성하게 되며, 서버는 결과 컨텐츠를 브라우저에 표시한다.

결과 보기

애플리케이션 아카이브는 두가지 스타일시트를 포함한다.

  • titles.xsl는 문서의 타이틀만을 표시한다.

다음은 타이틀 형식의 결과 집합의 일부를 출력한 것이다.

  • extended.xsl는 국립의학 도서관에서 지정한 표준 추천 도서목록에서 각 레코드를 서식화한다. 덧붙여 실제 인용 정보(저널 종류, 출판 날짜, 쪽수 등)가 PubMed 사이트의 전체 요약문으로 하이퍼링크된다.

따라서 다음의 출력물을 보면 이전과 같은 결과이지만 좀 더 확장된 형식을 보여줌을 알 수 있다.

입력폼에 삽입된 스타일시트를 이용하여 사용자의 기호에 맞는 스타일을 정의할 수도 있다. TEXTAREA 스타일시트는 스타일시트의 골격을 제공한다. 서블렛을 이용하여 간단한 검색을 실행해보자. 스타일시트를 지정하지 않은 채 결과 XML을 파일에 복사하고 이를 텍스트 에디터에서 새로운 스타일시트를 생성하기 위한 XML예제로 사용한다. 스타일시트 전체를 복사하여 form에 붙인 후 "Using custom XSL style:" 라디오 버튼을 클릭하여 Search를 선택한다. 스타일시트가 유효하다면 서블렛은 검색결과를 포맷하기 위해 이 스타일시트를 사용하게 될 것이다.

이 예제 서블렛을 확장하여 좀 더 유용하게 만드는 것도 어려운 일은 아니다. 예를 들어 PubMed로부터 대형 데이터를 다운로드 받아 분석하거나, 링크된 DNA 시퀀스를 표시하는 바이오정보 애플리케이션을 작성하기 위해 e-utilities의 다른 데이터베이스를 사용할 수도 있을 것이다.

"Java EE" 카테고리의 다른 글

Posted by 1010
반응형
XML 문서의 기본 구조

<?xml version="1.0" encoding="EUC-KR"?>

 

루트 엘리먼트로써 문서내에서 유일해야 하며, 나머지 구성요소는 루트 엘리먼트내에 위치해야 합니다.

<root></root>


루트 엘리먼트 자식 수준의 데이터를 xml문서라고 합니다.
        <name>홍길동</name>
        <age>30</age>
        <address>서울시 영등포구</address>

 


XML문서의 종료
    1. Well-Formed XML Document : XML 1.0 문법 준수
    2. Valid XML Document : DTD, Schema 문법 준수


 

인코딩
     1. ASCII : 7bit
     2. ISO Latin-1 : 8bit, 서유럽 문자코드 포함
     3. KS C5601 : 한국 공업표준, 2바이트 사용 -> 완성형 한글 표현
     4. EUC-KR : 영어(KS C5636) + 한글(KC C5601)
     5. Unicode
         1) UTF-8 : ASCII 문자(1바이트), 다른 문자(2바이트 이상), 한글 3바이트
         2) UTF-16 : 모든 문자 2바이트

 


엘리먼트 (Element)
   1. 시작태그와 끝태그는 항상 쌍을 이룹니다.
   2. 단독(빈)태그는 끝에 "/" 를 표시합니다.
   3. "<" 는 태그명으로 사용 불가능 합니다.
   4. "<" 와 ">" 사이에 공백사용이 불가능 합니다.
   5. 태그 중첩 사용이 불가능 합니다.
   6. 태그는 모든 문자로 시작 가능하지만, 숫자나 "." 사용 불가능 합니다.
   7. ":" 는 태그명으로 사용을 자제하는게 좋습니다.
   8. 대소문자를 구별합니다.

 


엘리먼트 (Element) 종류
   1. 내용을 가지는 Element (시작태그&끝태그)
       - <title>제목</title>
       - <head>
             <meta />
      </head>

   2. 내용을 가지지 않는 Element (시작태그) : 단독태그, 빈태그
       - <br />
       - <img />

   

 

엘리먼트 (Element)의 내용으로 올 수 있는 종류
    1. 문자 데이터
    2. 자식 엘리먼트
    3. 엔티티 & 문자참조 : <name>&nbsp;</name>

        ※ 문자 데이터와 엔티티는 전혀 틀리며, 이 때 name은 엔티티를 가진다고 합니다.
    4. CDATA Section : 해석되지 말아야 하는 데이터 집합으로 이 안에 태그등이 와도 태그로 인식하지 않습니다.
    5. 주석
    6. 공백 문자열 : 일반 문자 데이터와 틀립니다. (스페이스, 탭, 엔터 등)

 


속성 (Attribute)
   - 시작 엘리먼트에 포함되어야 합니다.
   - 속성명="속성값" or 속성명='속성값',
속성값은 " 나 ' 로 감싸줘야 합니다.
   - 속성명 명명법 : 엘리먼트명과 동일합니다

Posted by 1010
반응형

지각조퇴결석사유서.xml 문서 만들기

<?xml version="1.0" encoding="EUC-KR"?>
<?xml-stylesheet type="text/xsl" href="지각조퇴결석사유서.xsl"?>
<지각조퇴결석사유서>

 <과정>ASP.NET</과정>

 <기간>30일 완성</기간>
 <사유정보 번호="1">
  <성명>홍길동</성명>
  <주민번호>111111-1111111</주민번호>
  <구분 종류="지각"/>
  <날짜>2006.03.11</날짜>
  <사유>감기몸살로 -_-;;</사유>
 </사유정보>
 <사유정보 번호="2">
  <성명>아무게</성명>
  <주민번호>222222-2222222</주민번호 >
  <구분 종류="결석"/>
  <날짜>2006.04.15</날짜>
  <사유>
   <![CDATA[
   <strong>2007-06-28 12:30, coex megabox</strong><BR>
<BR>트렌스포머를 보러갔다.<BR>
<BR>처음부터 많은 기대를 하고 있었고 개방일만을 눈빠지게 기다리고 있던터라<BR>
<BR>개봉을 하자마자 달려가서 보았다.<BR>
<BR>아무튼 진부한 스토리라도 비주얼에 너무 정신을 빼앗기다 보니<BR>
<BR>스토리가 부실해도 상당히 재미있었다.<BR>
<BR>가장 기억에 남는 대사는 샘의 해피타임정도?<BR>]]>
  </사유>
 </사유정보>
 <사유정보 번호="3">
  <성명>테스트</성명>
  <주민번호>111111-1111111</주민번호>
  <구분 종류="지각"/>
  <날짜>2006.05.24</날짜>
  <사유>개인 사정</사유>
 </사유정보>
</지각조퇴결석사유서>


지각조퇴결석사유서.html 파일 만들기

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>Untitled Page</title>
  <script language="javascript">
   var xmlDoc;
   function startXml()
   {
    xmlDoc=new ActiveXObject("microsoft.XMLDOM");    
    xmlDoc.async=false;    
    xmlDoc.load("지각조퇴결석사유서.xml");
    document.getElementById("txtOutput").value=xmlDoc.xml;
   }
   
   function XmlInfo()
   {
    var result="";
    //루트 엘리먼트
    result += "Root Element : " + xmlDoc.documentElement.nodeName+"\n\n";
    //루트 엘리먼트의 첫번째 자식 엘리먼트
    result+="첫번째 자식 : "+xmlDoc.documentElement.firstChild.nodeName+"\n\n";
    //루트 엘리먼트의 마지막 자식 엘리먼트
    result+="마지막 자식 : "+xmlDoc.documentElement.lastChild.nodeName+"\n\n";
    //루트 엘리먼트의 두번째 자식 엘리먼트 (첫번째 방식)
    result+="두번째 자식 : "+xmlDoc.documentElement.childNodes.item(1).nodeName+"\n\n";
    //루트 엘리먼트의 두번째 자식 엘리먼트 (두번째 방식)
    result+="두번째 자식 : "+xmlDoc.selectNodes("//기간").item(0).nodeName+"\n\n";
    //사유정보 3번째의 이름 (첫번째 방식)
    result+="3번째 이름 : "+xmlDoc.documentElement.lastChild.firstChild.text+"\n\n";
    //사유정보 3번째의 이름 (두번째 방식)
    result+="3번째 이름 : "+xmlDoc.documentElement.childNodes(4).firstChild.text+"\n\n";
    //사유정보 3번째의 이름 (세번째 방식)
    result+="3번째 이름 : "+xmlDoc.selectNodes("//사유정보").item(2).firstChild.text+"\n\n";
    //사유 갯수
    result+="사유 갯수 : "+xmlDoc.selectNodes("//사유정보[구분 and @번호]").length+"개\n\n";
    //지각 갯수
    result+="사유 갯수 : "+xmlDoc.selectNodes("//구분[@종류='지각']").length+"개\n\n";
    //속성접근
    result+="2번째 종류 : "+xmlDoc.selectNodes("//사유정보").item(1).childNodes(2).attributes(0).value+"\n\n";

    alert(result);
   }  
  </script>
 </head>
 <body onload="startXml();">
  <h3>지각조퇴결석 사유서</h3>
  <textarea cols="120" rows="15" id="txtOutput"></textarea>
  <p></p>
  <button onclick="XmlInfo()" ID="Button1">XML 정보 보기</button>
 </body>
</html>

Posted by 1010
반응형

createElement.html 파일 만들기

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
 <head>
  <title></title>
  <script language="javascript">
   function Add()
   {
    var table1=document.getElementById("table1");
    var tr=document.createElement("tr");
    var td1=document.createElement("td");
    td1.innerText=document.all.txtName.value;
    var td2=document.createElement("td");
    td2.innerText=document.all.txtAddress.value;
   
    tr.appendChild(td1);
    tr.appendChild(td2);
    alert(table1.innerHTML);//테이블의 시작과 끝까지의 모든것.
    if(table1.firstChild.lastChild.childNodes.length==1)
    table1.firstChild.removeChild(table1.firstChild.lastChild);
    table1.firstChild.appendChild(tr);
   }
  </script>
 </head>
 <body>
  <h3>주소록</h3>
  <table border="1" width="300" id="table1">
   <tr>
    <th>이름</th>
    <th>주소</th>
   </tr>
   <tr>
    <td align="center" colspan="2">등록된 회원이 없습니다.</td>
   </tr>
  </table>
  <br />
  이름 : <input type="text" size="10" name="txtName" />
  주소 : <input type="text" size="10" name="txtAddress" />
  &nbsp;<button onclick="Add()">추가하기</button>
 </body>
</html>

Posted by 1010