xml.parsers.expat — Expat를 사용한 빠른 XML 파싱

xml.parsers.expat — Expat를 사용한 빠른 XML 파싱

xml.parsers.expat 모듈은 Expat non-validating XML 파서에 대한 Python 인터페이스예요. 이 모듈은 XML 파서의 현재 상태를 나타내는 단일 확장 타입 xmlparser를 제공해요. xmlparser 객체가 생성된 후, 객체의 다양한 속성을 핸들러 함수로 설정할 수 있어요. XML 문서가 파서로 공급되면, 핸들러 함수가 XML 문서의 문자 데이터와 마크업에 대해 호출돼요.

이 모듈은 pyexpat 모듈을 사용해 Expat 파서에 접근해요. pyexpat 모듈의 직접 사용은 폐기됐어요.

참고 — 신뢰할 수 없거나 인증되지 않은 데이터를 파싱해야 한다면 XML 보안을 참고하세요.

이 모듈은 다음 예외, 타입 객체, 데이터 항목을 제공해요:

출처: Python 표준 라이브러리

exception xml.parsers.expat.ExpatError

Expat가 오류를 보고할 때 발생하는 예외예요. Expat 오류를 해석하는 방법은 ExpatError 예외 절을 참고하세요.

exception xml.parsers.expat.error

ExpatError의 별칭이에요.

xml.parsers.expat.XMLParserType

ParserCreate() 함수의 반환 값의 타입이에요.

xml.parsers.expat.EXPAT_VERSION

인터프리터가 로드한 Expat 라이브러리의 버전 문자열로, 'expat_2.8.4' 같아요.

xml.parsers.expat.version_info

인터프리터가 로드한 Expat 라이브러리의 버전으로, major, minor, micro 버전의 세 정수 튜플이에요.

xml.parsers.expat.features

로드된 Expat 라이브러리가 컴파일된 기능의 리스트로, (name, value) 쌍이에요. 값은 값을 가진 기능에만 의미가 있어요. 예를 들어 'XML_CONTEXT_BYTES'나 기본 보호 한도인 'XML_BLAP_ACT_THRES''XML_AT_MAX_AMP' 같은 것. 'XML_DTD''XML_NS' 같은 다른 기능의 값은 0이고 이름의 존재만 중요해요.

xml.parsers.expat 모듈은 두 함수를 포함해요:

xml.parsers.expat.ErrorString(errno)

주어진 오류 번호 errno에 대한 설명 문자열을 반환해요.

xml.parsers.expat.ParserCreate(encoding=None, namespace_separator=None, intern=None)

xmlparser 객체를 만들어 반환해요. 지정되면 encoding은 XML 데이터가 사용하는 인코딩을 명명하는 문자열이어야 해요. Expat는 Python만큼 많은 인코딩을 지원하지 않고, 인코딩 레퍼토리를 확장할 수 없어요. UTF-8, UTF-16, ISO-8859-1(Latin1), ASCII를 지원해요. encoding [1]이 주어지면 문서의 암시적이거나 명시적인 인코딩을 덮어써요.

ParserCreate()로 만들어진 파서는 부모 파서가 붙어 있지 않다는 의미에서 "루트(root)" 파서라고 불려요. 비루트 파서는 parser.ExternalEntityParserCreate로 만들어져요.

Expat는 선택적으로 namespace_separator에 값을 제공해 XML 네임스페이스 처리를 할 수 있어요. 값은 한 문자 문자열이어야 해요. 문자열의 길이가 불법이면 ValueError가 발생해요(None은 생략과 동일하게 간주돼요). 네임스페이스 처리가 활성화되면 네임스페이스에 속한 요소 타입 이름과 속성 이름이 확장돼요. 요소 핸들러 StartElementHandlerEndElementHandler에 전달되는 요소 이름은 네임스페이스 URI, 네임스페이스 구분자 문자, 이름의 지역 부분의 연결이에요. 네임스페이스 구분자가 0바이트(chr(0))면 네임스페이스 URI와 지역 부분은 구분자 없이 연결돼요.

예를 들어 namespace_separator를 공백 문자(' ')로 설정하고 다음 문서를 파싱하면:

<?xml version="1.0"?>
<root xmlns    = "http://default-namespace.org/"
      xmlns:py = "http://www.python.org/ns/">
  <py:elem1 />
  <elem2 xmlns="" />
</root>

StartElementHandler는 각 요소에 대해 다음 문자열을 받아요:

http://default-namespace.org/ root
http://www.python.org/ns/ elem1
elem2

주어지면 intern은 사전이어야 해요. 요소와 속성의 이름을 intern하는 데 사용되며 intern 속성으로 사용 가능해요. 기본적으로 모든 파서에 대해 새 빈 사전이 만들어져요.

pyexpat이 사용하는 Expat 라이브러리의 제한 때문에 반환된 xmlparser 인스턴스는 단일 XML 문서를 파싱하는 데만 사용할 수 있어요. 각 문서에 대해 고유한 파서 인스턴스를 제공하려면 문서마다 ParserCreate를 호출하세요.

참고

본문

XMLParser 객체

xmlparser 객체에는 다음 메서드들이 있어요:

xmlparser.Parse(data[, isfinal])

data의 내용을 파싱하고, 적절한 핸들러 함수를 호출해 파싱된 데이터를 처리해요. data는 bytes 객체 또는 문자열일 수 있어요. 문자열이면 XML 데이터의 인코딩 선언은 무시되고, 데이터는 이미 디코딩된 텍스트로 파싱돼요. isfinal은 이 메서드에 대한 마지막 호출에서 참이어야 해요. 이것은 여러 파일을 제출하는 것이 아니라 단일 파일을 조각으로 파싱하는 것을 허용해요. data는 언제든지 비어 있을 수 있어요.

xmlparser.ParseFile(file)

객체 file에서 읽어 XML 데이터를 파싱해요. fileread(nbytes) 메서드를 제공하면 되는데, 그 메서드는 bytes를 반환하고 더 이상 데이터가 없으면 빈 bytes 객체를 반환해요. 텍스트 파일은 지원되지 않아요. 이미 디코딩된 데이터에는 Parse()를 사용하세요.

xmlparser.SetBase(base)

선언에서 시스템 식별자의 상대 URI를 해석하는 데 사용할 base를 설정해요. 상대 식별자 해석은 애플리케이션에 맡겨져요. 이 값은 ExternalEntityRefHandler(), NotationDeclHandler(), UnparsedEntityDeclHandler() 함수에 base 인자로 전달돼요.

xmlparser.GetBase()

이전 SetBase() 호출로 설정된 base를 담은 문자열을 반환하거나, SetBase()가 호출되지 않았으면 None을 반환해요.

xmlparser.GetInputContext()

현재 이벤트를 생성한 입력 데이터를 bytes 객체로 반환해요. 데이터는 그 텍스트를 포함하는 엔티티의 인코딩으로 돼 있어요. 현재 버퍼링된 입력의 끝까지 확장되므로, 이후 이벤트의 데이터도 포함할 수 있고, 이벤트가 많은 양의 텍스트로 생성되었다면 전부는 아닐 수 있어요. 이벤트 핸들러가 활성 상태가 아닐 때 호출되면 반환 값은 None이에요.

xmlparser.ExternalEntityParserCreate(context[, encoding])

부모 파서가 파싱한 내용이 참조하는 외부 파싱 엔티티를 파싱하는 데 사용할 수 있는 "자식" 파서를 만들어요. context 매개변수는 아래 설명된 ExternalEntityRefHandler() 핸들러 함수로 전달된 문자열이어야 해요. 자식 파서는 ordered_attributesspecified_attributes가 이 파서의 값으로 설정되어 만들어져요.

xmlparser.SetParamEntityParsing(flag)

매개변수 엔티티(외부 DTD 하위 집합 포함)의 파싱을 제어해요. 가능한 flag 값은 XML_PARAM_ENTITY_PARSING_NEVER, XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, XML_PARAM_ENTITY_PARSING_ALWAYS예요. flag 설정이 성공하면 true를 반환해요.

xmlparser.UseForeignDTD([flag])

flag(기본값)에 참 값을 주고 호출하면 Expat가 모든 인자에 None으로 ExternalEntityRefHandler를 호출해 대체 DTD를 로드할 수 있게 해요. 문서에 문서 타입 선언이 없으면 ExternalEntityRefHandler가 여전히 호출되지만 StartDoctypeDeclHandlerEndDoctypeDeclHandler는 호출되지 않아요.

flag에 거짓 값을 전달하면 참 값을 전달한 이전 호출을 취소하지만, 그 외에는 효과가 없어요. 이 메서드는 Parse() 또는 ParseFile() 메서드가 호출되기 전에만 호출할 수 있어요. 그 이후에 호출하면 code 속성이 errors.codes[errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING]으로 설정된 ExpatError가 발생해요.

xmlparser.SetReparseDeferralEnabled(enabled)

경고SetReparseDeferralEnabled(False) 호출에는 아래에 설명된 대로 보안 영향이 있어요. SetReparseDeferralEnabled 메서드를 사용하기 전에 그 결과를 이해했는지 확인하세요.

Expat 2.6.0은 "reparse deferral"이라는 보안 메커니즘을 도입했어요. 이 메커니즘은 큰 토큰을 다시 파싱할 때 이차 런타임을 통한 서비스 거부를 일으키는 대신, 미완료 토큰의 재파싱을 기본적으로 충분한 입력에 도달할 때까지 지연시켜요. 이 지연 때문에 등록된 핸들러는 — Expat으로 밀어 넣는 입력 청크의 크기에 따라 — 파서에 새 입력을 밀어 넣은 직후에는 더 이상 호출되지 않을 수 있어요. 즉각적인 피드백과 큰 토큰으로부터의 서비스 거부 보호 책임을 모두 원하는 경우, SetReparseDeferralEnabled(False)를 호출하면 현재 Expat 파서 인스턴스의 reparse deferral을 일시적으로 또는 완전히 비활성화해요. SetReparseDeferralEnabled(True)를 호출하면 reparse deferral을 다시 활성화할 수 있어요.

SetReparseDeferralEnabled()는 보안 수정으로 일부 이전 CPython 릴리즈에 백포트되었습니다. 다양한 Python 버전에서 실행되는 코드에서 사용한다면 hasattr()SetReparseDeferralEnabled()의 사용 가능 여부를 확인하세요.

버전 3.13에 추가.

xmlparser.GetReparseDeferralEnabled()

주어진 Expat 파서 인스턴스에 대해 reparse deferral이 현재 활성화되어 있는지 반환해요.

버전 3.13에 추가.

xmlparser 객체에는 몇 가지 일반적인 XML 취약점에 대한 보호를 조정하는 다음 메서드들이 있어요:

xmlparser.SetBillionLaughsAttackProtectionActivationThreshold(threshold, /)

billion laughs 공격에 대한 보호를 활성화하는 데 필요한 출력 바이트 수를 설정해요. 출력 바이트 수는 엔티티 확장과 DTD 파일 읽기로 인한 증폭을 포함해요.

파서 객체는 보통 8 MiB의 보호 활성화 임계값을 갖지만, 실제 기본값은 기본 Expat 라이브러리에 따라 달라요. 비루트 파서에서 이 메서드를 호출하면 ExpatError가 발생해요. 해당 linenooffset은 특별한 의미가 없을 수 있으므로 사용하지 말아야 해요.

참고 — 4 MiB 미만의 활성화 임계값은 DITA 1.3 페이로드 지원을 깨뜨리는 것으로 알려져 있어 권장되지 않아요.

버전 3.14.6에 추가.

xmlparser.SetBillionLaughsAttackProtectionMaximumAmplification(max_factor, /)

billion laughs 공격에 대한 보호를 위한 최대 허용 증폭 계수를 설정해요. 증폭 계수는 파싱 중에 (direct + indirect) / direct로 계산돼요. 여기서 direct는 파싱에서 기본 문서에서 읽은 바이트 수이고, indirect는 엔티티를 확장하고 외부 DTD 파일을 읽어 추가된 바이트 수예요.

max_factor 값은 1.0보다 크거나 같은 non-NaN float 값이어야 해요. 실제로 작은 양성 파일로 전체 페이로드에 대해 15,000, 파싱 중간에 30,000의 증폭 계수도 관찰됐어요. 특히 오탐을 피하기 위해 활성화 임계값을 신중하게 선택해야 해요.

파서 객체는 보통 최대 증폭 계수 100을 갖지만 실제 기본값은 기본 Expat 라이브러리에 따라 달라요. 비루트 파서에서 또는 max_factor가 유효 범위를 벗어나면 ExpatError가 발생해요. 해당 linenooffset은 특별한 의미가 없을 수 있으므로 사용하지 말아야 해요.

참고 — 최대 증폭 계수는 SetBillionLaughsAttackProtectionActivationThreshold()로 조정할 수 있는 임계값을 초과할 때만 고려돼요.

버전 3.14.6에 추가.

xmlparser.SetAllocTrackerActivationThreshold(threshold, /)

RAM의 불균형한 사용에 대한 보호를 활성화하는 데 필요한 동적 메모리 할당 바이트 수를 설정해요. 파서 객체는 보통 64 MiB의 할당 활성화 임계값을 갖지만 실제 기본값은 기본 Expat 라이브러리에 따라 달라요. 비루트 파서에서 이 메서드를 호출하면 ExpatError가 발생해요. 해당 linenooffset은 특별한 의미가 없을 수 있으므로 사용하지 말아야 해요.

버전 3.14.1에 추가.

xmlparser.SetAllocTrackerMaximumAmplification(max_factor, /)

직접 입력과 할당된 동적 메모리 바이트 사이의 최대 증폭 계수를 설정해요. 증폭 계수는 파싱 중에 allocated / direct로 계산돼요. 여기서 direct는 파싱에서 기본 문서에서 읽은 바이트 수이고, allocated는 파서 계층에서 할당된 동적 메모리의 바이트 수예요.

max_factor 값은 1.0보다 크거나 같은 non-NaN float 값이어야 해요. 실제로 양성 파일로도 파싱 시작 근처에서 100.0보다 큰 증폭 계수가 관찰될 수 있어요. 특히 오탐을 피하기 위해 활성화 임계값을 신중하게 선택해야 해요. 파서 객체는 보통 최대 증폭 계수 100을 갖지만 실제 기본값은 기본 Expat 라이브러리에 따라 달라요. 비루트 파서에서 또는 max_factor가 유효 범위를 벗어나면 ExpatError가 발생해요. 해당 linenooffset은 특별한 의미가 없을 수 있으므로 사용하지 말아야 해요.

참고 — 최대 증폭 계수는 SetAllocTrackerActivationThreshold()로 조정할 수 있는 임계값을 초과할 때만 고려돼요.

버전 3.14.1에 추가.

xmlparser 객체에는 다음 속성들이 있어요:

xmlparser.buffer_size

buffer_text가 참일 때 사용되는 버퍼의 크기예요. 이 속성에 새 정수 값을 할당해 새 버퍼 크기를 설정할 수 있어요. 크기가 바뀌면 버퍼가 비워져요(flush).

xmlparser.buffer_text

이것을 true로 설정하면 xmlparser 객체가 Expat이 반환한 텍스트 내용을 버퍼링해, 가능할 때마다 CharacterDataHandler() 콜백에 대한 여러 호출을 피해요. Expat는 보통 모든 줄 끝에서 문자 데이터를 청크로 나누므로 이것은 성능을 상당히 향상시킬 수 있어요. 이 속성은 기본적으로 false이고, 언제든지 바꿀 수 있어요. false일 때 줄바꿈을 포함하지 않는 데이터도 청크로 쪼개질 수 있다는 점에 주의하세요.

xmlparser.buffer_used

buffer_text가 활성화되면 버퍼에 저장된 바이트 수예요. 이 바이트들은 UTF-8 인코딩 텍스트를 나타내요. 이 속성은 buffer_text가 false일 때 의미 있는 해석이 없어요.

xmlparser.ordered_attributes

이 속성을 0이 아닌 정수로 설정하면 속성이 사전이 아닌 리스트로 보고돼요. 속성은 문서 텍스트에서 발견된 순서로 제시돼요. 각 속성에 대해 속성 이름과 속성 값 두 리스트 항목이 제시돼요. (이 모듈의 옛 버전도 이 형식을 사용했어요.) 기본적으로 이 속성은 false이고, 언제든지 바꿀 수 있어요.

xmlparser.specified_attributes

0이 아닌 정수로 설정하면 파서는 문서 인스턴스에 지정된 속성만 보고하고, 속성 선언에서 파생된 속성은 보고하지 않아요. 이것을 설정하는 애플리케이션은 XML 처리기 동작 표준을 준수하기 위해 선언에서 사용 가능한 추가 정보를 필요에 따라 사용하는 데 특히 주의해야 해요. 기본적으로 이 속성은 false이고, 언제든지 바꿀 수 있어요.

xmlparser.intern

요소와 속성의 이름을 intern하는 데 사용되는 사전이에요. ParserCreate()intern 인자로 전달된 사전 또는 이 파서를 위해 만들어진 새 사전이에요.

xmlparser.namespace_prefixes

참 값으로 설정되고 네임스페이스 처리가 활성화되면 네임스페이스 접두사가 확장 이름의 세 번째 부분으로, 네임스페이스 구분자로 구분되어 보고돼요. 접두사가 없는 이름은 영향을 받지 않아요. 기본적으로 이 속성은 false이고, 언제든지 바꿀 수 있어요.

다음 속성들은 xmlparser 객체가 만난 가장 최근 오류와 관련된 값을 담으며, Parse() 또는 ParseFile() 호출이 xml.parsers.expat.ExpatError 예외를 발생시킨 후에만 올바른 값을 가져요:

xmlparser.ErrorByteIndex

오류가 발생한 바이트 인덱스.

xmlparser.ErrorCode

문제를 지정하는 숫자 코드. 이 값은 ErrorString() 함수로 전달되거나 errors 객체에 정의된 상수 중 하나와 비교할 수 있어요.

xmlparser.ErrorColumnNumber

오류가 발생한 열 번호.

xmlparser.ErrorLineNumber

오류가 발생한 줄 번호.

다음 속성들은 xmlparser 객체의 현재 파싱 위치와 관련된 값을 담아요. 파싱 이벤트를 보고하는 콜백 동안 이벤트를 생성한 문자 시퀀스의 첫 위치를 나타내요. 콜백 밖에서 호출하면 표시된 위치는 마지막 파싱 이벤트 바로 뒤가 돼요(관련 콜백이 있었는지와 무관).

xmlparser.CurrentByteIndex

파서 입력의 현재 바이트 인덱스.

xmlparser.CurrentColumnNumber

파서 입력의 현재 열 번호.

xmlparser.CurrentLineNumber

파서 입력의 현재 줄 번호.

핸들러 목록 (Handlers)

설정할 수 있는 핸들러 목록은 다음과 같아요. xmlparser 객체 o에 핸들러를 설정하려면 o.handlername = func을 사용해요. handlername은 다음 목록에서 가져와야 하고, func는 올바른 인자 수를 받아들이는 callable 객체여야 해요. 달리 명시되지 않는 한 인자는 모두 문자열이에요.

xmlparser.XmlDeclHandler(version, encoding, standalone)

XML 선언이 파싱될 때 호출돼요. XML 선언은 (선택적) 해당 버전의 XML 권장 사항, 문서 텍스트의 인코딩, 선택적 "standalone" 선언이다. versionencoding은 문자열이고, standalone은 문서가 standalone으로 선언되면 1, 그렇지 않게 선언되면 0, standalone 절이 생략되면 -1이에요.

xmlparser.StartDoctypeDeclHandler(doctypeName, systemId, publicId, has_internal_subset)

Expat가 문서 타입 선언(<!DOCTYPE ...) 파싱을 시작할 때 호출돼요. doctypeName은 제시된 그대로 제공돼요. systemIdpublicId 매개변수는 지정되면 시스템·공용 식별자를 주고, 생략되면 None을 줘요. 문서에 내부 문서 선언 하위 집합이 있으면 has_internal_subset은 참이 돼요.

xmlparser.EndDoctypeDeclHandler()

Expat가 문서 타입 선언 파싱을 마쳤을 때 호출돼요.

xmlparser.ElementDeclHandler(name, model)

각 요소 타입 선언에 대해 한 번 호출돼요. name은 요소 타입의 이름이고, model은 내용 모델의 표현이에요.

xmlparser.AttlistDeclHandler(elname, attname, type, default, required)

요소 타입에 대해 선언된 각 속성에 대해 호출돼요. 속성 목록 선언이 세 속성을 선언하면 이 핸들러는 각 속성마다 한 번씩 세 번 호출돼요. elname은 선언이 적용되는 요소의 이름이고, attname은 선언된 속성의 이름이에요. 속성 타입은 type으로 전달되는 문자열이에요: 'CDATA', 'ID', 'IDREF', 'IDREFS', 'ENTITY', 'ENTITIES', 'NMTOKEN' 또는 'NMTOKENS', (x|y) 같은 열거, 또는 'NOTATION(n1|n2)' 같은 표기법 목록. default는 문서 인스턴스가 속성을 지정하지 않을 때 사용되는 속성의 기본값을 주고, 기본값이 없으면(#IMPLIED 값) None을 줘요. 문서 인스턴스에서 속성을 반드시 주어야 하면 required는 참이 돼요.

xmlparser.StartElementHandler(name, attributes)

모든 요소의 시작에 대해 호출돼요. name은 요소 이름을 담은 문자열이고, attributes는 요소 속성이에요. ordered_attributes가 참이면 이것은 리스트예요(전체 설명은 ordered_attributes 참고). 그렇지 않으면 이름을 값에 매핑하는 사전이에요.

xmlparser.EndElementHandler(name)

모든 요소의 끝에 대해 호출돼요.

xmlparser.ProcessingInstructionHandler(target, data)

모든 처리 명령에 대해 호출돼요.

xmlparser.CharacterDataHandler(data)

문자 데이터에 대해 호출돼요. 이것은 일반 문자 데이터, CDATA 표시 내용, 무시 가능한 공백에 대해 호출돼요. 이러한 경우를 구분해야 하는 애플리케이션은 StartCdataSectionHandler, EndCdataSectionHandler, ElementDeclHandler 콜백을 사용해 필요한 정보를 수집할 수 있어요. 문자 데이터는 짧아도 청크로 쪼개질 수 있으므로 CharacterDataHandler()에 둘 이상의 호출을 받을 수 있다는 점에 주의하세요. 이것을 피하려면 buffer_text 인스턴스 속성을 True로 설정하세요.

xmlparser.UnparsedEntityDeclHandler(entityName, base, systemId, publicId, notationName)

파싱되지 않은(NDATA) 엔티티 선언에 대해 호출돼요. 이 핸들러가 설정되지 않으면 그러한 선언은 새 코드에 선호되는 EntityDeclHandler가 보고해요. (Expat 라이브러리의 기본 함수는 쓸모없는 것으로 선언됐어요.)

xmlparser.EntityDeclHandler(entityName, is_parameter_entity, value, base, systemId, publicId, notationName)

모든 엔티티 선언에 대해 호출돼요. 매개변수 및 내부 엔티티의 경우 value는 엔티티의 선언된 내용을 주는 문자열이 돼요. 이것은 외부 엔티티의 경우 None이 돼요. notationName 매개변수는 파싱된 엔티티의 경우 None이고, 파싱되지 않은 엔티티의 경우 표기법의 이름이 돼요. is_parameter_entity는 엔티티가 매개변수 엔티티면 참, 일반 엔티티면 거짓이 돼요(대부분의 애플리케이션은 일반 엔티티에만 신경 쓰면 돼요).

xmlparser.NotationDeclHandler(notationName, base, systemId, publicId)

표기법 선언에 대해 호출돼요. notationName, base, systemId, publicId는 주어지면 문자열이에요. 공용 식별자가 생략되면 publicIdNone이 돼요.

xmlparser.StartNamespaceDeclHandler(prefix, uri)

요소가 네임스페이스 선언을 포함할 때 호출돼요. 네임스페이스 선언은 선언이 놓인 요소에 대해 StartElementHandler가 호출되기 전에 처리돼요.

xmlparser.EndNamespaceDeclHandler(prefix)

네임스페이스 선언을 포함한 요소의 닫는 태그에 도달했을 때 호출돼요. 각 네임스페이스 선언의 범위의 시작을 나타내기 위해 StartNamespaceDeclHandler가 호출된 순서의 역순으로, 요소의 각 네임스페이스 선언마다 한 번 호출돼요. 이 핸들러에 대한 호출은 요소 끝에 대한 해당 EndElementHandler 이후에 이루어져요.

xmlparser.CommentHandler(data)

주석에 대해 호출돼요. data는 선행 '<!--'와 후행 '-->'를 제외한 주석의 텍스트예요.

xmlparser.StartCdataSectionHandler()

CDATA 섹션의 시작에서 호출돼요. 이것과 EndCdataSectionHandler는 CDATA 섹션의 구문 시작과 끝을 식별하는 데 필요해요.

xmlparser.EndCdataSectionHandler()

CDATA 섹션의 끝에서 호출돼요.

xmlparser.DefaultHandler(data)

적용 가능한 핸들러가 지정되지 않은 XML 문서의 문자에 대해 호출돼요. 이는 보고될 수 있지만 핸들러가 제공되지 않은 구성을 구성하는 문자를 의미해요.

xmlparser.DefaultHandlerExpand(data)

DefaultHandler와 같지만, 내부 엔티티의 확장을 억제하지 않아요. 엔티티 참조는 기본 핸들러로 전달되지 않아요.

xmlparser.NotStandaloneHandler()

XML 문서가 standalone 문서로 선언되지 않은 경우 호출돼요. 외부 하위 집합이나 매개변수 엔티티에 대한 참조가 있지만 XML 선언이 standalone을 yes로 설정하지 않을 때 발생해요. 이 핸들러가 0을 반환하면 파서가 XML_ERROR_NOT_STANDALONE 오류를 발생시켜요. 이 핸들러가 설정되지 않으면 이 조건에 대해 파서가 예외를 발생시키지 않아요.

xmlparser.ExternalEntityRefHandler(context, base, systemId, publicId)

경고 — 로컬 파일 및/또는 네트워크에 접근하는 핸들러를 구현하면, xmlparser가 사용자 제공 XML 콘텐츠와 함께 사용될 때 외부 엔티티 공격에 대한 취약점을 만들 수 있어요. 이 핸들러를 구현하기 전에 위협 모델을 반영하세요.

외부 엔티티에 대한 참조에 대해 호출돼요. base는 이전 SetBase() 호출로 설정된 현재 base예요. 공용·시스템 식별자 systemIdpublicId는 주어지면 문자열이에요. 공용 식별자가 주어지지 않으면 publicIdNone이 돼요. context 값은 불투명하고 아래 설명된 대로만 사용해야 해요.

외부 엔티티가 파싱되도록 하려면 이 핸들러를 구현해야 해요. ExternalEntityParserCreate(context)를 사용해 하위 파서를 만들고, 적절한 콜백으로 초기화하고, 엔티티를 파싱하는 책임이 있어요. 이 핸들러는 정수를 반환해야 해요. 0을 반환하면 파서가 XML_ERROR_EXTERNAL_ENTITY_HANDLING 오류를 발생시켜요. 그렇지 않으면 파싱이 계속돼요.

이 핸들러가 제공되지 않으면 외부 엔티티는 제공된 경우 DefaultHandler 콜백이 보고해요.

xmlparser.SkippedEntityHandler(entityName, is_parameter_entity)

파서가 엔티티의 선언을 읽지 않았기 때문에 확장되지 않은 엔티티 참조에 대해 호출돼요. 외부 DTD 하위 집합 또는 외부 매개변수 엔티티가 파싱되지 않을 때 발생해요. is_parameter_entity는 매개변수 엔티티면 참, 일반 엔티티면 거짓이에요.

ExpatError 예외

ExpatError 예외는 몇 가지 흥미로운 속성을 가져요:

ExpatError.code

특정 오류에 대한 Expat의 내부 오류 번호예요. errors.messages 사전은 이 오류 번호를 Expat의 오류 메시지에 매핑해요. 예를 들어:

from xml.parsers.expat import ParserCreate, ExpatError, errors

p = ParserCreate()
try:
    p.Parse(some_xml_document)
except ExpatError as err:
    print("Error:", errors.messages[err.code])

errors 모듈은 또한 오류 메시지 상수와 오류 코드에 대한 메시지를 다시 매핑하는 codes 사전을 제공해요(아래 참고).

ExpatError.lineno

오류가 감지된 줄 번호. 첫 줄은 1로 번호가 매겨져요.

ExpatError.offset

오류가 발생한 줄 안의 문자 오프셋. 첫 열은 0으로 번호가 매겨져요.

예제 (Example)

다음 프로그램은 인자를 출력하기만 하는 세 핸들러를 정의해요.

import xml.parsers.expat

# 3 handler functions
def start_element(name, attrs):
    print('Start element:', name, attrs)
def end_element(name):
    print('End element:', name)
def char_data(data):
    print('Character data:', repr(data))

p = xml.parsers.expat.ParserCreate()

p.StartElementHandler = start_element
p.EndElementHandler = end_element
p.CharacterDataHandler = char_data

p.Parse("""<?xml version="1.0"?>
<parent id="top"><child1 name="paul">Text goes here</child1>
<child2 name="fred">More text</child2>
</parent>""", 1)

이 프로그램의 출력은 다음과 같아요:

Start element: parent {'id': 'top'}
Start element: child1 {'name': 'paul'}
Character data: 'Text goes here'
End element: child1
Character data: '\n'
Start element: child2 {'name': 'fred'}
Character data: 'More text'
End element: child2
Character data: '\n'
End element: parent

내용 모델 설명 (Content Model Descriptions)

내용 모델은 중첩된 튜플로 설명돼요. 각 튜플은 타입, 한정자(quantifier), 이름, 자식 튜플의 네 값을 담아요. 자식은 추가 내용 모델 설명일 뿐이에요. 처음 두 필드의 값은 xml.parsers.expat.model 모듈에 정의된 상수예요. 이 상수들은 모델 타입 그룹과 한정자 그룹의 두 그룹으로 수집될 수 있어요.

모델 타입 그룹의 상수는:

xml.parsers.expat.model.XML_CTYPE_ANY

모델 이름이 지정한 요소는 내용 모델이 ANY로 선언되었어요.

xml.parsers.expat.model.XML_CTYPE_CHOICE

이름이 지정된 요소는 여러 옵션 중에서 선택을 허용해요. (A | B | C) 같은 내용 모델에 사용돼요.

xml.parsers.expat.model.XML_CTYPE_EMPTY

EMPTY로 선언된 요소는 이 모델 타입을 가져요.

xml.parsers.expat.model.XML_CTYPE_MIXED

이름이 지정된 요소는 문자 데이터를 허용하고, 선택적으로 이름이 지정된 자식이 섞여 있어요. (#PCDATA)(#PCDATA | A | B)* 같은 내용 모델에 사용돼요.

xml.parsers.expat.model.XML_CTYPE_NAME

모델은 A처럼 단일 요소를 이름 지어요.

xml.parsers.expat.model.XML_CTYPE_SEQ

차례로 이어지는 일련의 모델을 나타내는 모델은 이 모델 타입으로 표시돼요. (A, B, C) 같은 모델에 사용돼요.

한정자 그룹의 상수는:

xml.parsers.expat.model.XML_CQUANT_NONE

수정자가 없어 A처럼 정확히 한 번 나타날 수 있어요.

xml.parsers.expat.model.XML_CQUANT_OPT

모델이 선택적이에요. A?처럼 한 번 또는 전혀 나타날 수 있어요.

xml.parsers.expat.model.XML_CQUANT_PLUS

모델은 A+처럼 한 번 이상 나타나야 해요.

xml.parsers.expat.model.XML_CQUANT_REP

모델은 A*처럼 0회 이상 나타나야 해요.

Expat 오류 상수 (Expat error constants)

다음 상수는 xml.parsers.expat.errors 모듈에 제공돼요. 이 상수들은 오류가 발생했을 때 발생한 ExpatError 예외 객체의 일부 속성을 해석하는 데 유용해요. 하위 호환성 이유로 상수의 값은 오류 메시지이지 숫자 오류 코드가 아니므로, code 속성을 errors.codes[errors.XML_ERROR_CONSTANT_NAME]과 비교해 이 작업을 수행해요.

errors 모듈에는 다음 속성이 있어요:

xml.parsers.expat.errors.codes

문자열 설명을 오류 코드에 매핑하는 사전이에요.

버전 3.2에 추가.

xml.parsers.expat.errors.messages

숫자 오류 코드를 문자열 설명에 매핑하는 사전이에요.

버전 3.2에 추가.

오류 상수는 다음과 같아요:

  • xml.parsers.expat.errors.XML_ERROR_ASYNC_ENTITY
  • xml.parsers.expat.errors.XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF — 속성 값의 엔티티 참조가 내부 엔티티가 아닌 외부 엔티티를 가리켰음.
  • xml.parsers.expat.errors.XML_ERROR_BAD_CHAR_REF — 문자 참조가 XML에서 불법인 문자를 가리켰음(예: 문자 0, 또는 '&#0;').
  • xml.parsers.expat.errors.XML_ERROR_BINARY_ENTITY_REF — 엔티티 참조가 표기법으로 선언된 엔티티를 가리켜 파싱할 수 없음.
  • xml.parsers.expat.errors.XML_ERROR_DUPLICATE_ATTRIBUTE — 시작 태그에서 속성이 두 번 이상 사용됨.
  • xml.parsers.expat.errors.XML_ERROR_INCORRECT_ENCODING
  • xml.parsers.expat.errors.XML_ERROR_INVALID_TOKEN — 입력 바이트가 문자에 제대로 할당될 수 없을 때 발생. 예: UTF-8 입력 스트림의 NUL 바이트(값 0).
  • xml.parsers.expat.errors.XML_ERROR_JUNK_AFTER_DOC_ELEMENT — 문서 요소 다음에 공백 외의 무언가가 발생함.
  • xml.parsers.expat.errors.XML_ERROR_MISPLACED_XML_PI — XML 선언이 입력 데이터의 시작이 아닌 다른 곳에서 발견됨.
  • xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS — 문서에 요소가 없음(XML은 모든 문서가 정확히 하나의 최상위 요소를 요구함).
  • xml.parsers.expat.errors.XML_ERROR_NO_MEMORY — Expat가 내부적으로 메모리를 할당할 수 없음.
  • xml.parsers.expat.errors.XML_ERROR_PARAM_ENTITY_REF — 매개변수 엔티티 참조가 허용되지 않는 곳에서 발견됨.
  • xml.parsers.expat.errors.XML_ERROR_PARTIAL_CHAR — 입력에서 불완전한 문자가 발견됨.
  • xml.parsers.expat.errors.XML_ERROR_RECURSIVE_ENTITY_REF — 엔티티 참조가 같은 엔티티에 대한 또 다른 참조를 포함함. 아마 다른 이름을 통해, 그리고 간접적으로도.
  • xml.parsers.expat.errors.XML_ERROR_SYNTAX — 지정되지 않은 어떤 구문 오류가 발생함.
  • xml.parsers.expat.errors.XML_ERROR_TAG_MISMATCH — 끝 태그가 가장 안쪽 열린 시작 태그와 일치하지 않음.
  • xml.parsers.expat.errors.XML_ERROR_UNCLOSED_TOKEN — 어떤 토큰(시작 태그 같은)이 스트림 끝이나 다음 토큰을 만나기 전에 닫히지 않음.
  • xml.parsers.expat.errors.XML_ERROR_UNDEFINED_ENTITY — 정의되지 않은 엔티티에 대한 참조가 이루어짐.
  • xml.parsers.expat.errors.XML_ERROR_UNKNOWN_ENCODING — 문서 인코딩이 Expat에서 지원되지 않음.
  • xml.parsers.expat.errors.XML_ERROR_UNCLOSED_CDATA_SECTION — CDATA 표시 섹션이 닫히지 않음.
  • xml.parsers.expat.errors.XML_ERROR_EXTERNAL_ENTITY_HANDLING
  • xml.parsers.expat.errors.XML_ERROR_NOT_STANDALONE — 파서가 문서를 "standalone"이 아닌 것으로 판단했는데 문서는 XML 선언에서 그렇게 선언했고, NotStandaloneHandler가 설정되어 0을 반환했음.
  • xml.parsers.expat.errors.XML_ERROR_UNEXPECTED_STATE
  • xml.parsers.expat.errors.XML_ERROR_ENTITY_DECLARED_IN_PE
  • xml.parsers.expat.errors.XML_ERROR_FEATURE_REQUIRES_XML_DTD — DTD 지원을 컴파일해야 하는 연산을 요청했지만 Expat가 DTD 지원 없이 구성됨. 표준 xml.parsers.expat 모듈 빌드에서는 보고되지 않아야 함.
  • xml.parsers.expat.errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING — 파싱 시작 후 파싱 시작 전에만 바꿀 수 있는 동작 변경을 요청함. (현재) UseForeignDTD()만 발생시킴.
  • xml.parsers.expat.errors.XML_ERROR_UNBOUND_PREFIX — 네임스페이스 처리가 활성화되었을 때 선언되지 않은 접두사가 발견됨.
  • xml.parsers.expat.errors.XML_ERROR_UNDECLARING_PREFIX — 문서가 접두사와 관련된 네임스페이스 선언을 제거하려고 시도함.
  • xml.parsers.expat.errors.XML_ERROR_INCOMPLETE_PE — 매개변수 엔티티가 불완전한 마크업을 포함함.
  • xml.parsers.expat.errors.XML_ERROR_XML_DECL — XML 선언을 파싱하는 데 오류가 있음.
  • xml.parsers.expat.errors.XML_ERROR_TEXT_DECL — 외부 엔티티의 텍스트 선언을 파싱하는 데 오류가 있음.
  • xml.parsers.expat.errors.XML_ERROR_PUBLICID — 공용 id에서 허용되지 않는 문자가 발견됨.
  • xml.parsers.expat.errors.XML_ERROR_SUSPENDED — 일시 중단된 파서에 요청된 연산을 하려 했지만 허용되지 않음. 추가 입력을 제공하거나 파서를 중지하는 시도를 포함함.
  • xml.parsers.expat.errors.XML_ERROR_NOT_SUSPENDED — 파서가 일시 중단되지 않았는데 파서를 재개하려고 시도함.
  • xml.parsers.expat.errors.XML_ERROR_ABORTED — Python 애플리케이션에 보고되어서는 안 됨.
  • xml.parsers.expat.errors.XML_ERROR_FINISHED — 입력 파싱을 마친 파서에 요청된 연산을 하려 했지만 허용되지 않음. 추가 입력을 제공하거나 파서를 중지하는 시도를 포함함.
  • xml.parsers.expat.errors.XML_ERROR_SUSPEND_PE
  • xml.parsers.expat.errors.XML_ERROR_RESERVED_PREFIX_XML — 예약된 네임스페이스 접두사 xml을 undeclare하거나 다른 네임스페이스 URI에 바인딩하려는 시도가 있었음.
  • xml.parsers.expat.errors.XML_ERROR_RESERVED_PREFIX_XMLNS — 예약된 네임스페이스 접두사 xmlns를 선언하거나 undeclare하려는 시도가 있었음.
  • xml.parsers.expat.errors.XML_ERROR_RESERVED_NAMESPACE_URI — 예약된 네임스페이스 접두사 xmlxmlns 중 하나의 URI를 다른 네임스페이스 접두사에 바인딩하려는 시도가 있었음.
  • xml.parsers.expat.errors.XML_ERROR_INVALID_ARGUMENT — Python 애플리케이션에 보고되어서는 안 됨.
  • xml.parsers.expat.errors.XML_ERROR_NO_BUFFER — Python 애플리케이션에 보고되어서는 안 됨.
  • xml.parsers.expat.errors.XML_ERROR_AMPLIFICATION_LIMIT_BREACH — 입력 증폭 계수(DTD와 엔티티로부터)의 제한이 위반됨.
  • xml.parsers.expat.errors.XML_ERROR_NOT_STARTED — 파서가 시작되기 전에 중지하거나 일시 중단하려는 시도가 있었음.

버전 3.14에 추가: XML_ERROR_NOT_STARTED.

각주

[1] XML 출력에 포함된 인코딩 문자열은 적절한 표준을 따라야 해요. 예를 들어 "UTF-8"은 유효하지만 "UTF8"은 그렇지 않아요. https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDeclhttps://www.iana.org/assignments/character-sets/character-sets.xhtml 참고.

더 알아보기