Как работать с XML-документом с необязательными узлами, где важна последовательность узлов

Мне нужно проанализировать следующий тип XML в объект Swift:

<grandparent>
    <parent_1 attr1="a">
        <child_1 attr1="b"/>
        <child_2 attr1="c"/>
    </parent_1>
    <parent_2 attr1="a">
        <child_1 attr1="b"/>
        <child_2 attr1="c"/>
    </parent_2>
    <parent_3 attr1="a">
        <child_1 attr1="b"/>
        <child_2 attr1="c"/>
    </parent_3>
</grandparent>

Каждый из родительских узлов является необязательным, но в любом порядке, в котором они определены выше, необходимо сохранить конечный объект Swift - в этом случае это массив с родителями 1,2,3 (если они все присутствовали).

Я не ясно, как это сделать с XMLMapper. У кого-нибудь есть предложения?

2 ответа

Вам нужно определить новый тег:

<parents>
  <parent id=1>...
  <parent id=2>..,
</parents>

Установите атрибут id.

Вы получите элемент родителей с родительскими детьми.

Сортировать массив по идентификатору:

array.sort(by: { $0.id < $1.id })

Начиная с версии 1.5.2 XMLMapper вы можете сохранить порядок элементов, используя nodesOrder собственностью XMLMap, Смотрите readme здесь.

Итак, вы можете отобразить ваш XML как:

class Grandparent: XMLMappable {
    var nodeName: String!

    var parent_1: Parent?
    var parent_2: Parent?
    var parent_3: Parent?
    var nodesOrder: [String]?

    required init?(map: XMLMap) {}

    func mapping(map: XMLMap) {
        parent_1 <- map["parent_1"]
        parent_2 <- map["parent_2"]
        parent_3 <- map["parent_3"]
        nodesOrder <- map.nodesOrder
    }
}

class Parent: XMLMappable {
    var nodeName: String!

    var attr1: String?
    var child_1Attr1: String?
    var child_2Attr1: String?

    required init?(map: XMLMap) {}

    func mapping(map: XMLMap) {
        attr1 <- map.attributes["attr1"]
        child_1Attr1 <- map.attributes["child_1.attr1"]
        child_2Attr1 <- map.attributes["child_2.attr1"]
    }
}

Вы можете сохранить порядок, просто не делая ничего, кроме обычного отображения:

let grandparent = Grandparent(XMLString: xmlString)

Или вы можете изменить его вручную:

let grandparent = Grandparent(XMLString: xmlString)
grandparent.nodesOrder = ["parent_1", "parent_3", "parent_2"]

Если у вас много родительских элементов и вы можете изменить предоставленный XML, вам, вероятно, следует использовать массив <parent> элементы, а не <parent_1>, <parent_2> а также <parent_3>

<grandparent>
    <parent attr1="a">
        <child_1 attr1="b"/>
        <child_2 attr1="c"/>
    </parent>
    <parent attr1="a">
        <child_1 attr1="b"/>
        <child_2 attr1="c"/>
    </parent>
    <parent attr1="a">
        <child_1 attr1="b"/>
        <child_2 attr1="c"/>
    </parent>
</grandparent>

В этом случае вы можете отобразить его в Array<Parent> и вам не нужно беспокоиться о заказе:

class Grandparent: XMLMappable {
    var nodeName: String!

    var parents: [Parent]?

    required init?(map: XMLMap) {}

    func mapping(map: XMLMap) {
        parents <- map["parent"]
    }
}

class Parent: XMLMappable {
    var nodeName: String!

    var attr1: String?
    var child_1Attr1: String?
    var child_2Attr1: String?

    required init?(map: XMLMap) {}

    func mapping(map: XMLMap) {
        attr1 <- map.attributes["attr1"]
        child_1Attr1 <- map.attributes["child_1.attr1"]
        child_2Attr1 <- map.attributes["child_2.attr1"]
    }
}

Надеюсь это поможет.

Другие вопросы по тегам