在 Swift 中附加元素后输出 XML 文档

Outputting an XML document in Swift after appending an element into it

提问人:markb 提问时间:9/24/2022 更新时间:9/24/2022 访问量:249

问:

在 Swift 中,有没有办法在通过函数传递 XML 文档后将元素添加到 XML 文档中?

例如,如果我将 的文本传入一个函数,我是否可以将其附加到 XML 文件中并将其另存为新的 XML 文档?<original>

输入 XML

<original>item-id-01</original>

自定义函数

func doThings(_ string: String) -> String { ... }
doThings("item-id-01")

输出 XML

<original>item-id-01</original>
<destination>output from custom function</destination>

我正在尝试在不使用库的情况下解析 XML 文件,但我看到的所有教程似乎都只展示了如何将一个元素追加到数组中,并将其显示到 UI 中。

也就是说,大多数示例:

<book>                        -->    struct Book {
  <title>My book</title>      -->      var title: String
  <author>Dr. ABC</author>    -->      var author: String
</book>                       -->    }

和 将搜索 ,然后将其附加到 的数组中。这似乎是XML解析的流行用途,因为它是JSON成为标准之前获取数据的方式。XMLParserXMLParserDelegateelementName == "book"var books: [Book]

但是,我希望能够传入我的XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<data version="1.2">
  <file file-location="Local/Folder/file-a.txt" original="192.168.0.1" destination="192.168.0.2">
    <header>
      <tool id="com.apple.TextEdit" name="TextEdit" version="14.0" build="123ABC"/>
    </header>
    <body>
      <item id="item-id-01" xml:space="preserve">
        <original>item-id-01</original>
        <note>Notes: no notes recorded</note>
      </item>
    </body>
  </file>
  <file file-location="Local/Folder/file-b.txt" original="192.168.10.1" destination="192.168.10.2">
    <header>
      <tool id="com.apple.TextEdit" name="TextEdit" version="14.0" build="123ABC"/>
    </header>
    <body>
      <item id="item-id-02" xml:space="preserve">
        <original>item-id-02</original>
        <note>Notes: no notes recorded</note>
      </item>
    </body>
  </file>
</data>

获取所有元素,将它们传递到函数中,并有一个如下所示的 XML 文档:<original>doThings()

<?xml version="1.0" encoding="UTF-8"?>
<data version="1.2">
  <file file-location="Local/Folder/file-a.txt" original="192.168.0.1" destination="192.168.0.2">
    <header>
      <tool id="com.apple.TextEdit" name="TextEdit" version="14.0" build="123ABC"/>
    </header>
    <body>
      <item id="item-id-01" xml:space="preserve">
        <original>item-id-01</original>
        <destination>output from custom function</destination> // <--- custom text
        <note>Notes: no notes recorded</note>
      </item>
    </body>
  </file>
  <file file-location="Local/Folder/file-b.txt" original="192.168.10.1" destination="192.168.10.2">
    <header>
      <tool id="com.apple.TextEdit" name="TextEdit" version="14.0" build="123ABC"/>
    </header>
    <body>
      <item id="item-id-02" xml:space="preserve">
        <original>item-id-02</original>
        <destination>output from custom function</destination> // <--- custom text
        <note>Notes: no notes recorded</note>
      </item>
    </body>
  </file>
</data>

当我使用 XMLParserDelegate 时,我能够将所有文本提取到模型数组中:<original>Item()

struct Item {
  var original: String
  var destination: String?
  var note: String
}

然后进入一个 String 数组,这样我就可以把它传递给我的函数:compactMapItem.original

let items: [Item] = []
let original: [String] = []

init() {
  items = XMLParser.getDataFrom(url: ...)
  orignal = items.compactMap({ $0.original })
}


func doThings(_ string: [String]) -> [String] { ... }

let output = doThings(original)

但是,我如何将原始XML文档注入到新文件中,并实质上“另存为......”呢?

我尝试过的事情

  • 将整个 XML 文档添加到它们自己的结构模型中,并遍历所有这些模型以重新构建

    • 这对我不起作用,因为我无法将属性导入模型并按原样输出
    • 例如。 到<file file-location="Local/Folder/file-a.txt" original="192.168.0.1" destination="192.168.0.2">
    struct File {
      var header: Header
      var body: Body
      var atributes: [String : String]
    }
    
  • 将 XML 转换为字符串,找到所有 并将其替换为</original></original><destination>loopValue[index]</destination>

  • 这不起作用,因为如果原始 XML 文档中已经有一个,那么我最终会得到<destination></original><destination>loopValue[index]</destination><destination>.. original document data</destination>


我是没有使用正确的 API,还是有没有实现此结果的好方法?

iOS Swift 结构 XML 解析

评论

0赞 Joakim Danielson 9/24/2022
我仍然不明白为什么你不能使用 XMLDocument,它有点麻烦,但肯定是这项工作的正确工具。
0赞 markb 9/24/2022
@JoakimDanielson XMLDocument 看起来很完美,但我无法让它与上面的示例 XML 文件一起使用。我显然做错了什么,但我找不到任何关于如何使用它的东西addChildinsertChild

答:

0赞 burnsi 9/24/2022 #1

如果你坚持

无需使用库

剩下的唯一选择是. 是一个低级的 Api,所以使用它并不是很有趣。libxml2libxml2C

因为会有另一种选择,但因为你被困住了.macOsXMLDocumentiosXMLParser

评论

0赞 markb 9/24/2022
不好意思!我输入了太多,我忘了说我只在做 macOS。所以 XMLParser
0赞 burnsi 9/24/2022
@markb我知道。因此,我对蜜蜂的评论卡住了。只是出于好奇,为什么不使用第三方库呢?其中大多数只是一个包装。libxml2
0赞 Joakim Danielson 9/24/2022 #2

下面是如何使用 XMLDocument 读取和更新 xml 的基本版本。请注意,我们在这里只处理类,所以一切都是通过引用的,这使得更新部分更简单一些。

let document = try! XMLDocument(xmlString: xmlString) //Change this to a suitable init

let nodes = try! document.nodes(forXPath: "/data/file/body/item")
for node in nodes {
    if var item = node as? XMLElement {
        let element = XMLNode.element(withName: "destination", stringValue: "some string value") as! XMLNode
        item.addChild(element)
    }
}

然后使用 or 提取并保存修改后的 xmldocument.xmlDatadocument.xmlString

而且你不应该像我在这里所做的那样到处使用try!:)