在 swift 中解析同名的 XML 子标签

Parse XML subtags with same name in swift

提问人:Daniel Fernandez 提问时间:4/23/2021 最后编辑:Daniel Fernandez 更新时间:4/24/2021 访问量:518

问:

我是 Swift 的新手。我创建了一个 XML 解析器,可以逐个读取每个标签(标签和子标签)。我发现的问题是有一些同名的子标签,所以我的代码无法区分。我需要知道如何读取具体的子标签以区分并将其存储在不同的变量中。

这是我正在解析的 XML(简化):

<_0:situationRecord id="GUID_Suc_3971318_3971318" xsi:type="_0:NetworkManagement">
    <_0:identifier>171826</_0:identifier>
    <_0:to xsi:type="_0:TPEGNonJunctionPoint">
        <_0:name>
            <_0:descriptor>
                <_0:value>MADRID</_0:value>
            </_0:descriptor>
            <_0:tpegDescriptorType>other</_0:tpegDescriptorType>
        </_0:name>
    </_0:to>
    <_0:from xsi:type="_0:TPEGNonJunctionPoint">
        <_0:name>
            <_0:descriptor>
                <_0:value>SANTIAGO DE COMPOSTELA</_0:value>
            </_0:descriptor>
            <_0:tpegDescriptorType>other</_0:tpegDescriptorType>
        </_0:name>
    </_0:from>
</_0:situationRecord>

这是我的ParseINCDGT.swift类:

import Foundation

struct INCIDENCIADGT {
    var identifier: String
    var valueFrom: String
    var valueTo: String
}

class ParseINCDGT: NSObject, XMLParserDelegate {
    private var myData: Data
    private var currentElementName = ""
    private var inItem = false
    private var item: INCIDENCIADGT
    var ready = false
    
    var auxLat = 1
    var auxLong = 1
    var aux = 1
    
    var items: [INCIDENCIADGT]
    
    override init() {
        //Default values
        myData = "".data(using: .ascii)!
        items = []
        item = INCIDENCIADGT(identifier: "", valueFrom: "", valueTo: "")
    }
    
    // Set the local data set for parsing
    func setData(data: Data) -> Void {
        if data == nil {
            return
        }
        myData = data
    }
    
    // Runs the parsing process, returns at the end. Please note that this function is synchronous, while internally asynchronous
    func parse() -> Void {
        let parser = XMLParser(data: myData)
        parser.delegate = self
        parser.parse()
    }
    
    // Terminate session
    func parserDidEndDocument(_ parser: XMLParser) {
        ready = true
    }
    
    // Start session
    func parserDidStartDocument(_ parser: XMLParser) {
        ready = false
    }
    
    // Terminate an element
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        currentElementName = elementName
        if elementName == "_0:situationRecord" {
            inItem = false
            items.append(item)
        }
    }
    
    // Starts an element
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        currentElementName = elementName
        if elementName == "_0:situationRecord" {
            inItem = true
            item = INCIDENCIADGT(identifier: "", valueFrom: "", valueTo: "")
        }
    }
    
    // Collects other data
    func parser(_ parser: XMLParser, foundCharacters string: String) {
        
        switch currentElementName{
        case "_0:identifier":
            item.identifier += string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        case "_0:value":
            item.valueFrom += string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        default:
            break
        }
    }
}

这是我调用ParserINCDGT.swift的方法:

func loadData() -> Void {
    let url = "http://infocar.dgt.es/datex2/dgt/SituationPublication/all/content.xml"
    let request = URLRequest(url: URL(string: url)!)
        
    let session3 = URLSession.shared.dataTask(with: request3) {
        (data, _, error) in
        
        //Handle errors
        if error != nil {
            //Show error message
            return
        }
        
        guard let data = data else{
            //Data error, show message
            return
        }
        
        //Convert data to string
        var s: String = String(data: data, encoding: .ascii)!
        
        //Make XML conforming to all standards: Convert LF to CR
        s = s.replacingOccurrences(of: "\r", with: "\n")
        
        //Parse XML
        let p = ParseINCDGT()
        p.setData(data: data)
        p.parse()
        
        //Elaborate data
        print(p.items)
        
        if (p.items.count != 0) {
            for item in p.items {
                print(item.identifier)
                print(item.valueFrom)
            }
        }
    }
    //Run!
    session.resume()
}

最后,变量“valueForm”的输出是“MADRIDSANTIAGO DE COMPOSTELA”

谁能帮我解释一下我应该包含什么来解析和区分子标签“_0:value”?

非常感谢。任何帮助都是值得赞赏的。

iOS Swift XML xml-解析

评论

0赞 Joakim Danielson 4/23/2021
您需要跟踪父标签是什么,这就是 XML 的设计方式。
0赞 Daniel Fernandez 4/23/2021
感谢您的回复。你能给我举个小例子吗?我是 swift 的新手。

答:

1赞 Jelumar 4/24/2021 #1

您只需要添加一些更改:

检查标签是否已启动并将其保存在变量中,我在这里调用了它,您需要将其添加到您的类中(private 会更好)。当您在其中查找文本时,请将其添加到 INCIDENCIADGT 结构的正确元素中。_0:from_0:toisFrom_0:value

Herer,您会看到两个需要更改的功能,需要添加的内容:

// Starts an element
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
    currentElementName = elementName
    if elementName == "_0:situationRecord" {
        inItem = true
        item = INCIDENCIADGT(identifier: "", valueFrom: "", valueTo: "")
    } else if elementName == "_0:from" { // check if we will be looking at from information when getting the next _0:value
        isFrom = true // could use an enum if more posibilities exist than from and to.
    } else if elementName == "_0:to" { // check if getting to information like above
        isFrom = false // could use an enum if more posibilities exist than from and to.
    }
}

// Collects other data
func parser(_ parser: XMLParser, foundCharacters string: String) {
    
    switch currentElementName{
    case "_0:identifier":
        item.identifier += string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
    case "_0:value":
        if isFrom { // write the information in the right field of the struct
            item.valueFrom += string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        } else {
            item.valueTo += string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
        }
    default:
        break
    }
}

我写的内容可能仍然存在一些错误和警告,因为我只是在编辑器中制作了它,并没有在 xcode 中对其进行测试,但如果它不起作用,它至少让您了解如何开始解决您的特定问题。

评论

1赞 Daniel Fernandez 4/27/2021
非常感谢您的回复。在周末将它调整为我的代码后,它运行良好。