programing

StAX보다 SAX를 언제 선택해야 합니까?

starjava 2023. 10. 9. 21:17
반응형

StAX보다 SAX를 언제 선택해야 합니까?

SAX 및 StAX와 같은 스트리밍 xml-pars는 DOM-pars와 같은 트리 구조를 구축하는 pars보다 빠르고 메모리 효율이 높습니다.SAX는 푸시 파서(push parser)로서 관찰자 패턴(listener pattern)의 한 예를 의미합니다.SAX가 처음에 있었지만 풀 파서인 StAX가 등장했습니다. 이는 기본적으로 반복기처럼 작동한다는 것을 의미합니다.

SAX보다 StAX를 선호하는 이유는 어디서나 찾을 수 있지만, 일반적으로 "사용하기가 더 쉽습니다."로 요약됩니다.

JAXP StAX에 대한 자바 튜토리얼에서는 모호하게 DOM과 SAX의 중간으로 제시되어 있습니다. "SAX보다 쉽고 DOM보다 효율적입니다." 하지만 StAX가 SAX보다 느리거나 메모리 효율이 낮을 것이라는 단서를 찾지 못했습니다.

StAX 대신 SAX를 선택해야 하는 이유가 있나요?


XML 문서는 동일한 요소 이름과 이름 공간이 여러 곳에서 발생하고 의미가 다르며 무한 깊이(재귀적)로 발생할 수 있는 계층적 문서입니다.평소처럼 큰 문제의 해결책은 작은 문제로 나누는 것입니다.XML 구문 분석의 맥락에서 이것은 XML의 특정 부분을 해당 XML에 특정한 방법으로 구문 분석하는 것을 의미합니다. 예를 들어, 하나의 논리는 주소를 구문 분석합니다.

<Address>
    <Street>Odins vei</Street>    
    <Building>4</Building>
    <Door>b</Door>
</Address>

즉, 당신은 방법이 있을 것입니다.

AddressType parseAddress(...); // A

아니면

void parseAddress(...); // B

XML 입력 인수를 사용하고 개체를 반환하는 논리의 어딘가에 있습니다(B의 결과는 나중에 필드에서 가져올 수 있음).


SAX는 XML 이벤트 '푸시'하므로 프로그램/데이터에서 XML 이벤트가 어디에 속할지 결정하는 것은 사용자에게 맡깁니다.

// method in stock SAX handler
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
    // .. your logic here for start element
}

Building' start 요소의 경우 Address(주소)를 실제로 구문 분석 중인지 확인한 다음 XML 이벤트를 Address(주소)를 해석하는 작업의 메서드로 라우팅해야 합니다.


StAX는 XML 이벤트 '풀'하므로 프로그램/데이터에서 XML 이벤트를 수신할 위치를 결정하는 것은 사용자에게 맡깁니다.

// method in standard StAX reader
int event = reader.next();
if(event == XMLStreamConstants.START_ELEMENT) {
    // .. your logic here for start element
}

물론 주소를 해석하는 작업을 수행하는 방법으로 항상 '빌딩' 이벤트를 받기를 원할 것입니다.


SAX와 StAX의 차이점은 밀고 당기는 것입니다.두 경우 모두 구문 분석 상태를 어떻게든 처리해야 합니다.

이는 SAX의 경우 일반적인 방법 B, StAX의 경우 방법 A로 해석됩니다.또한 SAX는 B에게 개별 XML 이벤트를 제공해야 하는 반면 StAX는 A에게 여러 개의 이벤트(XML StreamReader 인스턴스 통과)를 제공할 수 있습니다.

따라서 B는 먼저 구문 분석의 이전 상태를 확인한 다음 각 개별 XML 이벤트를 처리한 다음 (필드에) 상태를 저장합니다.메서드 A는 XML 스트림 리더에 여러 번 액세스하여 XML 이벤트를 한 번에 처리할 수 있습니다.


StAX를 사용하면 XML 구조에 따라 파싱(데이터 바인딩) 코드를 구성할 수 있습니다. 따라서 SAX와 관련하여 StAX의 경우 '상태'가 프로그램 흐름에서 암시적으로 나타나는 반면 SAX의 경우 대부분의 이벤트 호출에 대해 항상 일종의 상태 변수 + 해당 상태에 따라 흐름을 라우팅해야 합니다.

가장 간단한 문서를 제외한 모든 문서에 StAX를 추천합니다.나중에 최적화된 상태로 SAX로 이동하는 것이 좋습니다(그러나 그 때는 이진화 상태로 전환하는 것이 좋습니다).

StAX를 사용하여 구문 분석할 때는 다음 패턴을 따릅니다.

public MyDataBindingObject parse(..) { // provide input stream, reader, etc

        // set up parser
        // read the root tag to get to level 1
        XMLStreamReader reader = ....;

        do {
            int event = reader.next();
            if(event == XMLStreamConstants.START_ELEMENT) {
              // check if correct root tag
              break;
            }

            // add check for document end if you want to

        } while(reader.hasNext());

        MyDataBindingObject object = new MyDataBindingObject();
        // read root attributes if any

        int level = 1; // we are at level 1, since we have read the document header

        do {
            int event = reader.next();
            if(event == XMLStreamConstants.START_ELEMENT) {
                level++;
                // do stateful stuff here

                // for child logic:
                if(reader.getLocalName().equals("Whatever1")) {
                    WhateverObject child = parseSubTreeForWhatever(reader);
                    level --; // read from level 1 to 0 in submethod.

                    // do something with the result of subtree
                    object.setWhatever(child);
                }

                // alternatively, faster
                if(level == 2) {
                    parseSubTreeForWhateverAtRelativeLevel2(reader);
                    level --; // read from level 1 to 0 in submethod.

                    // do something with the result of subtree
                    object.setWhatever(child);
                }


            } else if(event == XMLStreamConstants.END_ELEMENT) {
                level--;
                // do stateful stuff here, too
            }

        } while(level > 0);

        return object;
}

따라서 하위 방법은 거의 동일한 접근법, 즉 계수 수준을 사용합니다.

private MySubTreeObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySubTreeObject object = new MySubTreeObject();
    // read element attributes if any

    int level = 1;
    do {
        int event = reader.next();
        if(event == XMLStreamConstants.START_ELEMENT) {
            level++;
            // do stateful stuff here

            // for child logic:
            if(reader.getLocalName().equals("Whatever2")) {
                MyWhateverObject child = parseMySubelementTree(reader);
                level --; // read from level 1 to 0 in submethod.

                // use subtree object somehow
                object.setWhatever(child);
            }

            // alternatively, faster, but less strict
            if(level == 2) {
              MyWhateverObject child = parseMySubelementTree(reader);
                level --; // read from level 1 to 0 in submethod.

                // use subtree object somehow
                object.setWhatever(child);
            }


        } else if(event == XMLStreamConstants.END_ELEMENT) {
            level--;
            // do stateful stuff here, too
        }

    } while(level > 0);

    return object;
}

그리고는 결국 기본 유형을 읽을 수 있는 수준에 도달하게 됩니다.

private MySetterGetterObject parseSubTree(XMLStreamReader reader) throws XMLStreamException {

    MySetterGetterObject myObject = new MySetterGetterObject();
    // read element attributes if any

    int level = 1;
    do {
        int event = reader.next();
        if(event == XMLStreamConstants.START_ELEMENT) {
            level++;

            // assume <FirstName>Thomas</FirstName>:
            if(reader.getLocalName().equals("FirstName")) {
               // read tag contents
               String text = reader.getElementText()
               if(text.length() > 0) {
                    myObject.setName(text)
               }
               level--;

            } else if(reader.getLocalName().equals("LastName")) {
               // etc ..
            } 


        } else if(event == XMLStreamConstants.END_ELEMENT) {
            level--;
            // do stateful stuff here, too
        }

    } while(level > 0);

    // verify that all required fields in myObject are present

    return myObject;
}

이것은 꽤 간단해서 오해의 여지가 없습니다.정확한 감소 수준을 기억해야 합니다.

A. 문자를 예상했지만 일부 태그에 문자가 포함되어야 하는 END_Element(END_Element)가 표시된 후(위 패턴에서):

<Name>Thomas</Name>

대신에

<Name></Name>

서브트리가 없어진 경우에도 마찬가지입니다.

B. 시작 요소에서 호출되고 해당 종료 요소 이후에 반환되는 하위 구문 분석 메서드 호출 후, 즉 구문 분석기는 메서드 호출 전보다 한 단계 낮은 수준입니다(위 패턴).

이 접근 방식이 보다 강력한 구현을 위해 '무시한' 공백 공간을 완전히 무시하는 방법에 주목하십시오.


대부분의 기능은 Woodstox를 사용하거나 속도는 Aaalto-xml을 사용합니다.

,StAX일 수 .SAX으로.StAX는 사실 이 있는지 가 없습니다.SAX레거시 코드로 작동하지 않는 한 파싱이 선호됩니다.

편집: 이 블로그에 따르면 Java SAXStAX. StAX스키마 유효성 검사를 제공하지 않습니다.

@Rinke: XML 콘텐츠를 처리/처리할 필요가 없을 때 SAX보다 SAX를 선호할 때만 생각합니다. 예를 들어, 들어오는 XML의 형식이 양호한지 확인하고 오류가 있는 경우에만 처리하고 싶습니다.이 경우 SAX 파서에서 단순히 parse() 메서드를 호출하고 오류 핸들러를 지정하여 파싱 문제를 처리할 수 있습니다. 기본적으로 SAX 컨텐츠 핸들러가 코드화하기가 너무 어렵기 때문에 컨텐츠를 처리하려는 시나리오에서는 STAX가 확실히 바람직한 선택입니다.

이 경우의 실질적인 예로는 일련의 SOAP 노드가 엔터프라이즈 시스템에 있는데 엔트리 레벨 SOAP 노드가 해당 SOAP XML이 다음 단계를 통과하도록 허용하는 경우를 들 수 있습니다. 이 경우 STAX를 사용할 이유가 없습니다.그냥 SAX로 할게요.

다 균형이에요.

SAX 파서는 차단 큐와 약간의 스레드 트릭을 사용하여 풀 파서로 전환할 수 있기 때문에, 저는 처음에 보였던 것보다 훨씬 적은 차이가 있습니다.

현재 StAX는 서드파티 jar를 통해 포장되어야 하고 SAX는 javax에서 무료로 제공된다고 생각합니다.

최근 SAX를 선택하여 주변에 풀 파서를 제작하여 타사 항아리에 의존할 필요가 없었습니다.

향후 버전의 Java에는 StAX 구현이 거의 확실하게 포함되어 있으므로 문제는 사라집니다.

StAX를 사용하면 빠른 양방향 XML 파서를 만들 수 있습니다.성능 및 사용성 측면에서 DOM 및 SAX와 같은 다른 방법에 비해 더 나은 대안임을 입증합니다.

Java StAX 튜토리얼에서 StAX에 대한 자세한 내용을 읽을 수 있습니다.

그 답변들이 제공하는 대부분의 정보는 다소 구식입니다...이 2013년 연구 논문에는 모든 XML 구문 분석 라이브러리에 대한 포괄적인 연구가 있습니다.그것을 읽으면 당신은 명백한 승자를 쉽게 볼 수 있을 것입니다(hint: 진정한 승자는 단 한 명뿐입니다).

http://recipp.ipp.pt/bitstream/10400.22/1847/1/ART_BrunoOliveira_2013.pdf

언급URL : https://stackoverflow.com/questions/7521803/when-should-i-choose-sax-over-stax

반응형