이 도구는 샘플 XML을 읽어 그 구조를 설명하는 Go 타입을 만듭니다. 먼저 XML을 XML to JSON 변환기와 같은 규칙의 데이터로 바꾸고, 그 데이터에서 구조체를 생성합니다. 중첩 요소는 구조체가, 키는 대문자로 시작하는 필드가 되며 json:"..." 태그에는 속성 앞의 @까지 원래 키가 그대로 남습니다.
태그가 json인 것은 의도입니다. 이 구조체는 원본 XML에 encoding/xml을 쓰는 용도가 아니라, 변환된 데이터에 encoding/json을 쓰는 용도입니다. XML을 encoding/xml로 바로 읽으려면 필드 목록만 가져가서 태그를 xml:"id,attr", xml:",chardata" 형태로 직접 고쳐야 합니다.
파서는 이 페이지를 위해 만든 엄격한 XML 1.0 파서입니다. 문서가 잘못되면 정확한 행과 열을 알려 주고 편집기에서 해당 줄을 강조합니다. 입력은 20 MiB까지 받고, XML은 브라우저 밖으로 나가지 않습니다.
사용 방법
XML 붙여넣기 또는 예제 선택
문서를 붙여 넣거나 API 응답, 중첩 배열, 엣지 케이스 예제를 불러옵니다. 입력하는 대로 결과가 바뀌므로 변환 버튼은 없습니다.
XML 데이터 매핑 정하기
속성 접두사(기본
@), 텍스트 키(기본#text), 자식 하나도 항상 목록으로 둘지, 숫자와 불리언을 해석할지 고릅니다. 이 규칙은 모든 XML 변환기가 공유합니다.Go 옵션 정하기
루트 타입 이름(기본
Payload)과 패키지(기본models)를 적고, 빠진 필드에 포인터를 쓸지, omitempty를 언제 붙일지(사용 안 함, 선택 필드만, 모든 필드)를 고릅니다.구조체 읽기
루트 구조체가 맨 위에 오고 중첩 구조체는 처음 만난 순서로 이어집니다. 혼합 콘텐츠 같은 경고는 코드 위에 표시됩니다.
복사 또는 다운로드
코드를 복사하거나
.go파일로 내려받습니다. 파일 이름은 루트 타입을 스네이크 케이스로 바꾼 것이라 기본값은payload.go입니다.
작동 원리
XML에서 데이터로, 데이터에서 Go로
속성은 접두사가 붙은 키가 되고, 속성이나 자식 요소 옆에 있는 텍스트는 텍스트 키 아래에 들어가며, 이름이 같은 형제 요소는 배열이 됩니다. 루트 요소가 최상위의 유일한 키이므로 루트 구조체에는 필드가 정확히 하나 있습니다. CDATA는 텍스트로 취급하며 숫자로 바꾸지 않습니다.
| XML | 데이터 키 | Go 필드 |
|---|---|---|
<a>x</a> | a | A string, 태그 json:"a" |
id="7" | @id | ID int, 태그 json:"@id" |
id="007" | @id | ID string, 앞자리 0이 있어 문자열 유지 |
| 속성 옆의 텍스트 | #text | Text string, 태그 json:"#text" |
반복되는 <item> | item | Item []PayloadItem |
<empty/> | empty | Empty string, 빈 요소는 빈 문자열 |
<ok>true</ok> | ok | Ok bool |
필드 이름, 숫자, 선택 필드
Go 필드 이름은 접두 문자를 뺀 키를 파스칼 케이스로 바꾼 것이며 흔한 약어는 대문자가 됩니다. 그래서 @id는 ID, xml:lang은 XMLLang이 됩니다. 숫자로 시작하는 이름에는 Field가 붙고 겹치는 이름에는 숫자가 붙습니다. 태그에 정확한 키가 들어 있으므로 @id나 #text도 올바르게 디코딩됩니다.
타입 추론을 켜면 정수는 2147483647까지 int, 그보다 크면 int64, 소수는 float64, true/false는 bool이 됩니다. 반복 요소는 모든 발생을 하나의 구조체로 합치고, 일부 발생에만 있는 키는 *int 같은 포인터와 omitempty가 되어 nil이 없음을 뜻합니다. 슬라이스와 any에는 포인터를 씌우지 않습니다.
type PayloadOrderItem struct {
Sku string `json:"@sku"`
Qty *int `json:"@qty,omitempty"`
Text string `json:"#text"`
}요소 하나만 달라져도 구조가 바뀌는 이유
<item>이 하나면 객체, 둘 이상이면 배열로 매핑되므로 샘플에 따라 Go 타입이 구조체였다가 슬라이스였다가 달라집니다. 자식 요소는 항상 배열로 옵션을 켜면 샘플에 하나뿐이어도 슬라이스가 되므로, 실제 데이터의 개수가 들쭉날쭉할 때 이 옵션이 맞습니다.
실제 예시
<order id="1042"><item sku="A1" qty="1">Pen</item><item sku="B7">Ink</item></order>package models
type Payload struct {
Order PayloadOrder `json:"order"`
}
type PayloadOrder struct {
ID int `json:"@id"`
Item []PayloadOrderItem `json:"item"`
}
type PayloadOrderItem struct {
Sku string `json:"@sku"`
Qty *int `json:"@qty,omitempty"`
Text string `json:"#text"`
}두 item 요소가 하나의 구조체로 합쳐집니다. qty는 첫 번째에만 있어 *int와 omitempty가 되고, 요소의 텍스트는 Text 필드입니다.
<p><zip>02134</zip><qty>3</qty><price>19.5</price><ok>true</ok><note><![CDATA[42]]></note></p>package models
type Payload struct {
P PayloadP `json:"p"`
}
type PayloadP struct {
Zip string `json:"zip"`
Qty int `json:"qty"`
Price float64 `json:"price"`
Ok bool `json:"ok"`
Note string `json:"note"`
}02134는 앞자리 0 때문에 문자열로 남고 3은 int, 19.5는 float64, true는 bool이 됩니다. CDATA의 42는 추론하지 않으므로 string입니다.
<cart><item id="1">Pen</item></cart>package models
type Payload struct {
Cart PayloadCart `json:"cart"`
}
type PayloadCart struct {
Item []PayloadCartItem `json:"item"`
}
type PayloadCartItem struct {
ID int `json:"@id"`
Text string `json:"#text"`
}샘플에 item이 하나뿐이어도 필드가 []PayloadCartItem이므로 여러 개가 든 장바구니도 같은 구조체로 디코딩됩니다.
자주 하는 실수
xml 태그가 아니라 json 태그입니다
encoding/xml은@id나#text를 모릅니다. 변환된 데이터를encoding/json으로 디코딩하거나,encoding/xml에 맞게 태그를 고쳐 쓰세요.요소 하나일 때와 여러 개일 때
항상 배열 옵션 없이
<item>이 하나뿐인 샘플로 만들면 구조체 필드가 되어, 나중에 item이 둘인 문서는 언마셜 타입 오류로 실패합니다. 개수가 달라질 수 있으면 옵션을 켜세요.정수처럼 보이는 소수
19.0은 숫자 19로 읽히므로 필드가int가 되고, 나중에19.5가 오면 들어맞지 않습니다. 타입 추론을 끄면 모든 값이 문자열로 남으니, 아니면 타입을 직접 고치세요.한 번만 나온 필드
선택 키는 샘플에 있는 발생끼리 비교해 찾으므로, 값이 일부만 있는 항목도 샘플에 넣어야 합니다. 샘플에 한 번도 없는 키는 필드가 생기지 않고
json.Unmarshal이 조용히 무시합니다.
자주 묻는 질문
encoding/xml용 태그도 만들어 주나요?
아니요. XML 매핑으로 얻은 데이터에 대한 json 태그를 만듭니다. 속성 필드는 json:"@이름", 텍스트는 json:"#text" 태그가 붙습니다.
속성 태그 앞의 @를 없앨 수 있나요?
네. XML 데이터 매핑 패널에서 속성 접두사를 비우거나 _처럼 바꾸면 됩니다. Go 필드 이름은 그대로고 태그만 바뀝니다.
반복 요소는 어떤 타입이 되나요?
구조체 하나의 슬라이스가 되고, 텍스트만 있는 요소는 []string입니다. 모든 발생을 합치므로 구조체는 모든 키의 합집합을 갖습니다.
왜 어떤 필드는 포인터인가요?
일부 발생에서 키가 빠져 있었기 때문입니다. 포인터를 쓰면 nil로 없음을 표현할 수 있고, 0 값이 좋다면 포인터 옵션을 끄면 됩니다.
네임스페이스는 어떻게 나오나요?
접두사가 붙은 이름은 쓴 그대로 유지되어 ns:entry는 태그가 json:"ns:entry"인 NsEntry 필드가 됩니다. 네임스페이스 선언은 해석하지 않습니다.
XML이 어딘가로 업로드되나요?
아니요. 파싱과 생성이 모두 페이지 안에서 실행되고 문서는 기기에 남습니다.
마지막 업데이트:
