MYMONDAY.ai
서비스스튜디오도구데이터·포맷73CSS 생성기19색상·이미지10인코딩·보안10웹·SEO11개발·데브옵스10파일·내보내기18계산기6가이드

XML Swift Codable 변환기

샘플 XML을 Codable 구조체로 바꾸며, CodingKeys에 속성과 텍스트의 정확한 키를 남깁니다.

  • 브라우저에서 처리
  • 가입 없음
  • 무료

도구 작업 공간

예제

옵션

XML → 데이터 매핑

속성은 이 문자로 시작하는 키가 되어 id="1"은 @id가 됩니다. 비우면 속성 이름 그대로 씁니다.

속성이나 자식 요소와 함께 있는 텍스트는 이 키에 담습니다.

끄면 <item>이 하나일 땐 객체, 여러 개일 땐 배열이 됩니다. 켜면 개수와 상관없이 구조가 같습니다.

끄면 모든 값이 문자열로 남습니다. 켜면 true/false, 정수, 소수는 해당 타입이 되고 007이나 긴 ID는 문자열로 둡니다.

XML 입력

21줄491byte

결과

⌘/Ctrl + Enter로 복사
결과 · Payload.swift
import Foundation

struct Payload: Codable {
    let order: PayloadOrder
}

struct PayloadOrder: Codable {
    let id: Int
    let status: String
    let customer: PayloadOrderCustomer
    let items: PayloadOrderItems
    let total: Double
    let shippedAt: String
    let tracking: String

    enum CodingKeys: String, CodingKey {
        case id = "@id"
        case status = "@status"
        case customer
        case items
        case total
        case shippedAt = "shipped_at"
        case tracking
    }
}

struct PayloadOrderCustomer: Codable {
    let id: Int
    let vip: Bool
    let name: String
    let email: String

    enum CodingKeys: String, CodingKey {
        case id = "@id"
        case vip = "@vip"
        case name
        case email
    }
}

struct PayloadOrderItems: Codable {
    let item: [PayloadOrderItemsItem]
}

struct PayloadOrderItemsItem: Codable {
    let sku: String
    let qty: Int
    let name: String
    let price: Double

    enum CodingKeys: String, CodingKey {
        case sku = "@sku"
        case qty = "@qty"
        case name
        case price
    }
}
타입5
크기1.1kB

이 도구는 샘플 XML에 대한 Swift Codable 구조체를 씁니다. 모든 XML 변환기가 공유하는 규칙으로 XML을 데이터로 매핑하고, 속성이나 자식이 있는 요소마다 구조체가 하나 생깁니다. 프로퍼티는 기본적으로 let이며 스위프트 이름을 쓰므로 키 @data-id는 프로퍼티 dataId가 됩니다.

프로퍼티 이름이 키와 다르면 구조체에 모든 프로퍼티를 나열한 enum CodingKeys: String, CodingKey가 생기고 case sku = "@sku"처럼 원래 철자가 들어갑니다. 그러면 JSONDecoder가 키 전략 없이도 변환된 JSON을 디코딩합니다. 원본 XML을 읽는 구조체는 아니며, 그러려면 XMLParser나 XML 코더 라이브러리가 필요합니다.

입력은 엄격한 XML 1.0 파서가 읽고 오류에는 정확한 행과 열을 알려 줍니다. 20 MiB까지 페이지 안에서 처리하며 업로드하지 않습니다.

사용 방법

  1. XML 붙여넣기

    문서를 붙여 넣거나 예제를 고릅니다. 입력할 때마다 구조체가 갱신됩니다.

  2. 매핑 설정

    XML 데이터 매핑 패널에서 속성 접두사, 텍스트 키, 항상 배열, 숫자 추론을 고릅니다.

  3. Swift 옵션 선택

    루트 타입 이름(기본 Payload)과, let 대신 var를 쓸지를 정합니다.

  4. CodingKeys 검토

    키가 프로퍼티 이름과 다른 구조체에만 CodingKeys가 생깁니다. 모든 프로퍼티가 나열됐는지 확인하세요.

  5. 복사 또는 다운로드

    코드를 복사하거나 루트 타입 이름의 Payload.swift로 내려받습니다.

작동 원리

타입과 옵셔널

여기서 스위프트는 정수형과 부동소수점형을 하나씩만 쓰므로 정수는 모두 Int, 소수는 모두 Double입니다. 일부 발생에 없는 키는 ?가 붙은 옵셔널이 되고, Codable이 decodeIfPresent를 자동으로 만들어 줍니다.

XMLSwift
<name>Ada</name>let name: String
id="7"let id: Int, case id = "@id"
<price>19.5</price>let price: Double
<ok>true</ok>let ok: Bool
반복되는 <item>let item: [PayloadItem]
일부 item에만 있는 키let qty: Int?
<v>1</v><v>a</v>[JSONValue]와 JSONValue 열거형

CodingKeys와 JSONValue 보조 타입

스위프트 식별자에는 @, #, :, -를 쓸 수 없으므로 이런 키는 lowerCamelCase로 바뀌고 원래 키는 CodingKeys에 남습니다. CodingKeys를 선언하면 모든 프로퍼티를 나열해야 하므로 case customer처럼 이름 변경이 필요 없는 항목도 함께 들어갑니다.

한 위치에 종류가 섞인 값이 있으면 문자열, 숫자, 불리언, 객체, 배열, null을 다루는 indirect enum JSONValue: Codable이 파일 끝에 한 번 추가됩니다.

struct PayloadOrderItem: Codable {
    let sku: String
    let qty: Int?
    let text: String

    enum CodingKeys: String, CodingKey {
        case sku = "@sku"
        case qty = "@qty"
        case text = "#text"
    }
}

단일 자식과 배열

<item>이 하나면 중첩 구조체, 둘이면 배열이 됩니다. 항상 배열 스위치를 켜면 샘플에 하나뿐이어도 [PayloadItem]이 되어 긴 문서에서 JSONDecoder가 typeMismatch를 던지지 않습니다.

실제 예시

반복 항목이 있는 주문
입력
<order id="1042"><item sku="A1" qty="1">Pen</item><item sku="B7">Ink</item></order>
출력
import Foundation

struct Payload: Codable {
    let order: PayloadOrder
}

struct PayloadOrder: Codable {
    let id: Int
    let item: [PayloadOrderItem]

    enum CodingKeys: String, CodingKey {
        case id = "@id"
        case item
    }
}

struct PayloadOrderItem: Codable {
    let sku: String
    let qty: Int?
    let text: String

    enum CodingKeys: String, CodingKey {
        case sku = "@sku"
        case qty = "@qty"
        case text = "#text"
    }
}

키 이름이 바뀐 구조체마다 모든 프로퍼티를 나열한 CodingKeys가 생깁니다. qty는 첫 번째 item에만 있어 Int?입니다.

네임스페이스와 하이픈이 있는 이름
입력
<doc xml:lang="en" data-id="5"><title>Hi</title></doc>
출력
import Foundation

struct Payload: Codable {
    let doc: PayloadDoc
}

struct PayloadDoc: Codable {
    let xmlLang: String
    let dataId: Int
    let title: String

    enum CodingKeys: String, CodingKey {
        case xmlLang = "@xml:lang"
        case dataId = "@data-id"
        case title
    }
}

@xml:lang과 @data-id는 xmlLang, dataId가 되고, 키와 이름이 같은 title은 이름만 있는 case로 충분합니다.

한 이름에 섞인 종류
입력
<r><v>1</v><v>a</v></r>
출력
import Foundation

struct Payload: Codable {
    let r: PayloadR
}

struct PayloadR: Codable {
    let v: [JSONValue]
}

indirect enum JSONValue: Codable {
    case string(String)
    case number(Double)
    case bool(Bool)
    case object([String: JSONValue])
    case array([JSONValue])
    case null

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if container.decodeNil() { self = .null; return }
        if let value = try? container.decode(Bool.self) { self = .bool(value); return }
        if let value = try? container.decode(Double.self) { self = .number(value); return }
        if let value = try? container.decode(String.self) { self = .string(value); return }
        if let value = try? container.decode([String: JSONValue].self) { self = .object(value); return }
        if let value = try? container.decode([JSONValue].self) { self = .array(value); return }
        throw DecodingError.dataCorruptedError(in: container, debugDescription: "Unsupported JSON value")
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let value): try container.encode(value)
        case .number(let value): try container.encode(value)
        case .bool(let value): try container.encode(value)
        case .object(let value): try container.encode(value)
        case .array(let value): try container.encode(value)
        case .null: try container.encodeNil()
        }
    }
}

같은 요소 이름에 숫자와 단어가 있으면 하나의 스위프트 타입으로 쓸 수 없어 v는 [JSONValue]가 되고 보조 열거형이 붙습니다.

자주 하는 실수

  • CodingKeys 없이는 이름이 맞지 않습니다

    프로퍼티 이름을 직접 바꿨다면 case 줄도 함께 고치세요. id라는 프로퍼티로는 키 @id를 디코딩할 수 없습니다.

  • Int는 64비트 플랫폼에서만 64비트입니다

    2^53보다 큰 ID는 추론 규칙에 따라 String으로 남지만, 그 아래의 큰 숫자는 32비트 대상에서 Int 범위를 넘을 수 있습니다.

  • 정수처럼 보이는 소수

    19.0은 숫자 19로 읽혀 프로퍼티가 Int가 되고, 나중에 19.5가 오면 디코딩에 실패합니다. 추론을 끄거나 타입을 Double로 고치세요.

  • XMLParser용 모델이 아닙니다

    이 구조체는 JSON을 디코딩합니다. XMLParser나 XML 코더는 @sku 같은 키가 아니라 요소 이름과 속성을 찾습니다.

자주 묻는 질문

모든 구조체에 CodingKeys가 생기나요?

키가 스위프트 프로퍼티 이름과 다른 항목이 하나라도 있는 구조체에만 생깁니다. 키가 모두 같다면 자동 합성되는 키를 씁니다.

프로퍼티가 왜 옵셔널인가요?

그 요소의 일부 발생에 해당 키가 없었기 때문입니다. 옵셔널이면 JSONDecoder가 예외 대신 nil로 둡니다.

변경 가능 옵션은 무엇을 바꾸나요?

모든 프로퍼티를 let 대신 var로 써서 디코딩한 뒤에도 값을 고칠 수 있게 합니다.

keyDecodingStrategy와 같이 써도 되나요?

필요 없습니다. CodingKeys에 정확한 키가 이미 있어서 convertFromSnakeCase 같은 전략은 오히려 방해가 됩니다.

리스트는 어떤 타입이 되나요?

합쳐진 구조체의 배열이며 예를 들어 [PayloadItem], 텍스트만 있는 요소는 [String]입니다.

XML이 업로드되나요?

아니요. 모든 처리가 브라우저에서 이뤄지고 문서는 기기에 남습니다.

마지막 업데이트: