apple / swift-corelibs-foundation

The Foundation Project, providing core utilities, internationalization, and OS independence
swift.org
Apache License 2.0
5.23k stars 1.12k forks source link

XMLElement.attribute(forName:) doesnt work when root node has xmlns: tag #4943

Open stevenbrix opened 2 months ago

stevenbrix commented 2 months ago

If the root of the XML document has a default xmlns namespace definition, then XMLElement.attribute(forName:) will incorrectly return nil.

Repro steps

  1. Save the following to an xml file (say, c:\temp\foo.xml):
    <?xml version="1.0" encoding="utf-8"?>
    <AppInstaller
    Version="99.99.99.100" xmlns="http://schemas.microsoft.com/appx/appinstaller/2018">
    <MainPackage
        Version="99.99.99.100"/>
    </AppInstaller>
  2. Create a new swift executable project, and replace main function with the following:
let xmlFile = "file:///c:/temp/foo.xml"
let doc = try XMLDocument(contentsOf: URL(fileURLWithPath: xmlFile)!)
let mainPackage = doc.rootElement()!.elements(forName: "MainPackage")[0]
print(mainPackage.attribute(forName: "Version"))
  1. swift run the project

Expected

Console prints Optional( Version="99.99.99.100")

Actual

Console prints nil

Other Notes

  1. Simply removing the xmlns="http://schemas.microsoft.com/appx/appinstaller/2018" from the root doc makes things work as expected.
  2. this can be worked around with the following extension:
private extension XMLElement {
    func knownAttributeValue(forName: String) -> String {
        for attribute in attributes ?? [] {
            guard forName == attribute.name, let value = attribute.stringValue else { continue }
            return value
        }

        fatalError("No attribute named \(forName) found")
    }
}