losLab PDF Library는 XFA 3.3 SOM 경로 표현식(SOM path expressions)을 지원하여 동적 XFA 양식 내의 반복 데이터 노드들을 읽고 씁니다: GetXFAFormFieldValue 및 SetXFAFormFieldValue 함수는 $data, $record, !data 루트와 [*] 와일드카드, 자손 및 자식 와일드카드 선택자, parent 속성, #dataGroup/#dataValue 클래스 선택자, 그리고 간단한 FormCalc 스타일의 조건자(predicates) 사양을 완벽히 지원하므로, Delphi 프로그램을 통해 정부 세무 양식 등의 모든 인보이스 항목 행 데이터를 단 한 번의 호출로 갱신할 수 있습니다. 본 기사는 경로 지정법에 집중해 설명하며, 파일 간 데이터 세트 일괄 이송 기능에 대해서는 FDF, XFDF 및 XFA 양식 데이터 교환 가이드 기사를 참고하십시오
오류 및 구조적 난관은 양식 지면이 비대칭 구조(non-flat)를 띠는 순간부터 도드라집니다. 동적 XFA 규격으로 작성된 부가세 신고서나 세관 신고용 문서의 경우, Total_Price_1부터 Total_Price_12까지 12개의 평면 필드를 두어 데이터를 채우지 않습니다; 대신 템플릿 DOM 내에 Detail 서브폼 하나만을 선언해 두고 데이터 입력 요건에 맞춰 런타임에 동적으로 반복 복제해 사용합니다. 입력값들은 데이터셋 패킷 내의 별도 트리인 데이터 DOM에 저장되며, 개별 인보이스 항목들은 <Receipt> 노드 하위의 반복된 <Detail> 노드 구조를 취합니다. 이 구조 하에서 단순 파일명만으로는 "세 번째 줄의 단가 정보"나 "금액이 200을 초과하는 행들 전체"와 같은 데이터를 조작할 수 없습니다; Adobe XFA 3.3 표준 규격서의 Scripting Object Model 챕터에서 이 조작을 위해 규정한 사양이 바로 SOM 표현식이며, losLab PDF Library의 XFA field-value API들도 이 표준 구문을 완벽히 해독해 작동합니다
Delphi에서 XFA 데이터 노드를 어떻게 참조합니까?
모든 데이터셋 경로는 루트에서 시작하며, losLab PDF Library는 표준 표기명들을 혼용 수용합니다: $data는 XFA 3.3의 xfa.datasets.data 단축 표기명이며, !data는 xfa.datasets를 원점으로 가리키는 단축명이고, 레코드 단독 프로세스를 사용하지 않는 패킷의 경우 $record는 외부 데이터 레코드의 첫 번째 엘리먼트 데이터 노드를 자동으로 참조합니다. 템플릿 연동 API인 SetXFAFormFieldAccess 등도 $template 및 xfa.template 표기를 동일한 방식으로 인식합니다. 각 노드 구획선은 점(.) 또는 슬래시(/) 기호로 기입할 수 있습니다($data.Receipt.Tax or $data/Receipt/Tax). 특히 GetXFAFormFieldNames는 필드 이름 리스트를 슬래시 기호 구획선 경로로 나열하여 반환하므로 이를 값 제어 API에 고대로 대입해 쓸 수 있어 요긴합니다. 규격에 따라 반복 요소의 인덱스 번호는 0부터 시작하므로 Detail[0]이 첫 번째 행을 가리킵니다. 특수 기호가 포함된 노드 이름을 참조하기 위해 두 가지 이스케이프(escaping) 규칙을 지원합니다: 점 구획선 경로 상에서 \.은 노드 이름 내의 실제 마침표 기호(Line\.Item)를 지시하며, 슬래시 구획선 경로 상에서는 마침표가 일반 문자로 수용됩니다. XML 네임스페이스 접두사(prefix)가 결합된 비즈니스 데이터의 경우 접두사가 생략된 로컬 이름 매칭을 연동하므로 <m:Receipt>는 Receipt 이름만으로 깔끔하게 조회됩니다
var
Lib: TPDFlib;
Tax: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('vat-return.pdf', '');
// Equivalent addresses for the same data node
Tax := Lib.GetXFAFormFieldValue('Receipt.Tax');
Tax := Lib.GetXFAFormFieldValue('$data.Receipt.Tax');
Tax := Lib.GetXFAFormFieldValue('xfa.datasets.data.Receipt.Tax');
Tax := Lib.GetXFAFormFieldValue('$record.Tax');
// Slash form with a zero-based occurrence index
Lib.SetXFAFormFieldValue('$record/Detail[0]/Total_Price', '251.00');
Lib.SaveToFile('vat-return-updated.pdf');
finally
Lib.Free;
end;
end;
프로그래밍 방식으로 XFA 양식의 반복 행 데이터를 어떻게 채웁니까?
[*] 와일드카드는 일괄 처리를 돕는 도구입니다. 특정 정수 인덱스 번호 대신 [*]를 사용하면 동일한 이름을 가진 형제 노드들 전체를 일괄 참조합니다. 따라서 $data.Receipt.Detail[*].Total_Price 경로는 모든 반복 행들의 단가 필드를 한 번에 지정합니다. 데이터 조회 시 GetXFAFormFieldValue는 매칭된 모든 노드의 값들을 파이프라인(|) 문자로 엮어 하나의 문자열로 반환하며, 쓰기 시 SetXFAFormFieldValue는 해당 매칭 노드들 전체에 대입 값을 일괄 적용하고 성공 시 1을 반환합니다. 매칭 대상이 없는 무효한 경로는 예외 대신 빈 문자열을 반환하므로, 쓰기 전에 타겟 노드 브랜치 존재 유무를 확인하는 안전장치로 쓰기 적합합니다
var
Lib: TPDFlib;
Prices: WideString;
begin
Lib := TPDFlib.Create;
try
Lib.LoadFromFile('invoice.pdf', '');
// All Detail rows at once: '250.00|60.00'
Prices := Lib.GetXFAFormFieldValue('$data.Receipt.Detail[*].Total_Price');
// Reset one column across every repeated row in a single call
Lib.SetXFAFormFieldValue('$data.Receipt.Detail[*].Surcharge', '0.00');
Lib.SaveToFile('invoice-updated.pdf');
finally
Lib.Free;
end;
end;
자손, 자식 와일드카드 및 부모 선택자
구조 정의를 정확히 모르고 필드 식별자 이름만 파악하고 있는 경우 활용하기 적합한 3가지 구조 선택자 사양을 제공합니다. 자손 선택자인 ..은 현재 노드 하위의 모든 깊이에 대해 조회를 적용합니다: 즉 $data..Total_Price는 데이터 루트 하위의 임의 깊이에 존재하는 첫 번째 Total_Price 노드를 찾아내며, 값 쓰기 시 해당 첫 매칭 노드를 업데이트합니다. 한 가지 제약점: 자손 선택자 매칭 후의 인덱스 번호 부여는 형제 노드 범위를 교차 탐색하지 못합니다. 즉 $data..Total_Price[0]이 첫 번째 Detail 행 내부의 필드에 안착했다면 $data..Total_Price[1]은 다음 행으로 넘어가지 않고 빈 결과를 반환합니다. 다중 순회를 원한다면 Detail[*] 형식을 명시하십시오. 자식 와일드카드인 .*은 직계 자식 노드 전체를 탐색한 후 뒤의 경로 조회를 연동합니다: 예를 들어 $data.Receipt.*.Total_Price는 Receipt의 모든 직계 자식 하위의 Total_Price를 탐색하면서 Receipt 노드 자체에 직접 박혀 있는 동일 이름의 요약 정보 필드는 안전하게 배제합니다. 마지막으로 parent 속성은 상위 부모 노드로 한 단계 올라가며, XFA 3.3 표준은 이를 자손 선택자 ..과 엄격히 구별해 정의합니다: $data.Receipt.Detail[1].parent.Taxstarts at the second line item, steps up to Receipt, and lands on its sibling Tax value
클래스 선택자 및 조건자: #dataGroup, #dataValue, .[식]
#class 구문은 XML 태그 내에 스크립트 특수 기호 등으로 식별하기 까다로운 텍스트 문자가 섞여 있을 때 노드 식별자 이름 대신 객체의 클래스 정보로 데이터 DOM을 조회하는 매우 실질적인 해법입니다. losLab PDF Library는 하위 엘리먼트 자식을 가진 노드를 #dataGroup으로 맵핑하고 자식이 없는 단독 값 리프 노드를 #dataValue로 분류하여 정수 인덱스 및 와일드카드 조합을 완벽 지원합니다: $data.Receipt.#dataGroup[0].#dataValue[0]은 Receipt 하위 첫 번째 그룹의 첫 번째 리프 값 노드를 정확히 지시합니다. 조건자 선택자 .[식]은 동일한 형제 노드들의 내용을 조건 필터링해 줍니다. 지원 조건식은 리프 단독 값과 리터럴의 단순 대조 검사이며 대소 비교(>, <, <= 등)가 수용됩니다. 다중 행이 조건에 매칭되는 경우 조회 시 파이프라인 문자 결합식으로, 쓰기 시 일괄 쓰기 형태로 작동합니다
// Flag every line whose Total_Price exceeds 200
Lib.SetXFAFormFieldValue(
'$data.Receipt.Detail.[Total_Price > 200].Review_Flag', '1');
// Descriptions of all low-value lines, '|'-joined when several match
Desc := Lib.GetXFAFormFieldValue(
'$data.Receipt.Detail.[Total_Price <= 200].Description');
// Class-based addressing when tag names resist script spelling
Total := Lib.GetXFAFormFieldValue(
'$data.Receipt.#dataGroup[0].#dataValue[0]');
XFA SOM 지원 제약 조건
losLab PDF Library의 SOM 지원 범위는 데이터셋과 템플릿 필드 경로 분석에 한정되며, 일부 지원되지 않는 스펙 사양은 다음과 같습니다. 미리 숙지해 두어야 조회가 되지 않고 빈 문자열만 뜨는 버그 상황을 면할 수 있습니다
- 조건식(Predicates)은 임의의 FormCalc 또는 JavaScript 구문을 실행하지 않습니다: 즉 함수 호출식(예:
contains(...)등)은 조회 불통 처리되며 복합 논리 합산식 대신 단일 대조자식 연산자 리터럴연산만 작동합니다 $record는 레코드 단위 분할 패킷이 미적용된 일반 패킷 상에서만 작동합니다; dataWindow의 레코드 페이징 및 그룹 회전 제어 기능은 지원되지 않습니다- 경로는 데이터 DOM 및 템플릿 DOM을 직접 조회합니다; 뷰어 화면 렌더링 시 런타임 상에 실시간 병합되는 양식(Form) DOM의 상대 매핑 처리 구조는 직접 거치지 않습니다
- 데이터 DOM 속성(attribute) 로딩 기법은 구현에서 제외되어 있습니다; 라이브러리는 데이터셋 패킷을 XML 데이터로만 읽어 들이므로, 경로는 XML 속성이 아닌 엘리먼트 노드 주소만을 참조합니다
대부분의 배치 데이터 기입 실무에서는 노드의 구조적 참조에만 의존하므로 이러한 제약 사양이 걸림돌이 되는 경우는 매우 드묾니다. 만약 이 제약 처리를 극복해야 한다면 데이터셋 XML 정보 전체를 메모리에 통째로 로드하여 Delphi의 XMLDocument 등으로 기가공한 뒤 덮어쓰는 방식을 취하십시오
SetXFAFromString을 사용한 패킷 단위 일괄 쓰기
SetXFAFromString은 이 패킷 단위 제어의 다이렉트 통로입니다: XDP 템플릿과 데이터셋 데이터 전체를 내포한 XML 문자열을 일괄 세팅해 주며, AcroForm 컨테이너 구조가 생략된 문서 상에 필요한 컨테이너도 자동 빌드해 장착해 줍니다. UTF-8 부호화 외에 UTF-16 부호화 패킷 문서도 안전하게 디코딩해 수용합니다. 흔히 활용되는 아키텍처 패턴은 표준 XDP 서식을 자원으로 미리 보존해 두고 SetXFAFromString으로 지면 기초 폼을 생성한 뒤, SOM 경로 표현식이 적용된 SetXFAFormFieldValue 호출로 세부 개별 행 값만 실시간 대입해 최종 문서를 빌드 출력하는 방식입니다. XFA 외에 PDF가 탑재하는 다른 양식 규격인 클래식 AcroForm 제어 사양에 대해서는 대화형 양식 제어 및 JavaScript 연동 기사에서 설명합니다
본문에서 예시된 XFA 필드 제어, 목록화 및 패킷 연동 API 기능들은 Delphi, C# 및 VB.NET용 losLab PDF Library의 기본 내장 표준 사양으로 제공됩니다