Search code examples
swiftobjective-cxcodemacosnsdocument

NSDocument XML read Issue


I am working on a NSDocument based Mac app. Which imports .xml file. It's working fine for some xml files but for few having issues.

Issue is read() is modifying the data when we import file, i need to keep the original data as it is. what do i need to do to make sure i get original xml data in the read()?

I am using below function to read the file

override func read(from data: Data, ofType typeName: String) throws {
    var error:NSError? = nil
    var xmlDocument1:XMLDocument? = XMLDocument()
    do{
        xmlDocument1 = try XMLDocument(data: data, options: XMLNode.Options(rawValue: XMLNode.Options.RawValue(Int(XMLNode.Options.nodePreserveWhitespace.rawValue))))
    }catch let err as NSError{
        error = err
    }
    if error != nil {
        throw error!
    }
}

and i parse xmlDocument1 to read and get all the xml information.

Issue: Doing this way swift is modifying the document, as mentioned below.

Example 1:

Original:

<iws:attr-option name="1 - Poor" /> 
<iws:attr-option name="2 - Needs Improvement" />

Data getting from Read(), notice the closing tags added automatically

<iws:attr-option name="1 - Poor"></iws:attr-option>
<iws:attr-option name="2 - Needs Improvement"></iws:attr-option>

Example 2:

Original:

<source>
    <ph id="12" x="&lt;/span>">{12}</ph>
</source>

Data getting from Read(), notice the ">" symbol is replaced with "& gt;"

<source>
    <ph id="12" x="&lt;/span&gt;">{12}</ph>
</source>

Example 3:

I am not able to paste the code here as the special character is not even displaying here, so adding image. left is the original and right side one is what i am getting in read(), special character is missing.

enter image description here

Code Sameple : (I am not sure if we can post code directly here) https://drive.google.com/drive/folders/1WWGE7fFJPKvs5KU5f_PlwWtoqCVxTcS0?usp=sharing

  1. Above drive we have sample xml file and code.
  2. "DevelopingADocumentBasedApp" is the code, just open the "DocumentBasedApp.xcodeproj", run it. 3 .Once it runs, click on Menu->File->Open and open the provided xml file.
  3. In content.swift, Keep a break point at "print(xmlDocument!)"
  4. Here we can see the document is modified by NSDocument, and it is different from the original

Edit:

@matt Thank you for making me understand real problem, Initially i thought that i have issue with NSDocument's read(). But issues is XMLDocument() not returning exact data. I need to find a solution for that.



Solution

  • Reading is not changing your document.

    You make an xml document, with XMLDocument(data:...). You are asking for a new valid XML document based on your original, and that is exactly what you get. The resulting structure is not a big string, like your original data; it is an elaborate node tree reflecting the structure of your XML. That node tree is identical to the structure described by your original. That fact does not affect in any way your ability to parse the document; indeed, it is why you are able to parse the document. If you think it does cause an inability to parse the document, your parsing code is wrong (but you didn't show that, so no more can be said).

    Also note that your evidence for what is "in" the XML document is indirect; the XML document is a node tree, but the strings you display are the output of a secondary rendering into a string. That rendering representation is arbitrary and malleable; it obeys its own rules of formatting. (And again, you didn't show anything about how you obtain that rendering. Perhaps we are talking about your print statement?)

    The point is, you seem to have to some sort of expectation about how passing into an XMLDocument and then back out of it will "round trip" your original string in such a way that the output looks just like the original. That expectation is incorrect. That's not what XMLDocument does.

    And merely reading the original data into an XMLDocument did not change the data, I can promise you that.

    So don't worry, be happy; as far as the validity of your XML is concerned, everything is fine, and the data you started with has not been altered in any way.


    Here's a demonstration:

    let xmlstring = """
    <testing>
    <fun whatever="thingy" />
    </testing>
    """
    print(xmlstring)
    let xmldata = xmlstring.data(using: .utf8)!
    let xml = try? XMLDocument(data: xmldata, options: [])
    print("=======")
    print(xml!)
    

    The output is:

    <testing>
    <fun whatever="thingy" />
    </testing>
    =======
    <?xml version="1.0"?><testing><fun whatever="thingy"></fun></testing>
    

    As you can see, the output from the print is not the same as the input string. But it is a valid XML representation of the original string, and that's all that matters. And the original xmlstring and xmldata that I started with are, I assure you, completely untouched.