Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialized XML Object - How to get parent node #277

Open
waelsaad opened this issue Oct 26, 2023 · 9 comments
Open

Deserialized XML Object - How to get parent node #277

waelsaad opened this issue Oct 26, 2023 · 9 comments

Comments

@waelsaad
Copy link

waelsaad commented Oct 26, 2023

Hi @drmohundro I hope all is well. I have a question please, I have created a deserialize XML structure but I am trying to figure out how I can have access to a parent node.

Here is an example of one of my structs, the title can appear at top level or in a nested node and I am hoping find a generic way when I render the structure to know the parent node for the title. is there a way to tell a parent node? do I need to add an extension to XMLIndexer?

	struct Title: HashedNode {
		var parent: NodeType?
		var languages: [LanguageNode]
		let children: [XMLNode]

		static func deserialize(_ node: XMLIndexer) throws -> Title {
			if let parent = node.type {
				print(parent)
			}
			return Title(
				languages: try node["Language"].value(),
				children: try node.children.map { try XMLNode.deserialize($0) }
			)
		}
	}

I tried setting my own version of parent like this but its still nil when I try to render title.

	struct Section: HashedNode {
		var title: Title?
		let children: [XMLNode]

		static func deserialize(_ node: XMLIndexer) throws -> Section {

			var title: Title?
			do {
				title = try node["Title"].value() as Title
				title?.parent = .section
			} catch {
				// Handle any errors when deserializing the title
				// You might want to log or handle the error here
			}

			return Section(
				title: title,
				children: try node.children.map { try XMLNode.deserialize($0) }
			)
		}
	}

Thank you

@drmohundro
Copy link
Owner

Question... from a node, would you want to be able to get an XMLElement as a parent so that you could see the element name?

Also, I'm wondering if, when deserializing the parent type, when calling the .value() on the child elements, you could pass in a parent type then instead of having the child element be able to refer back up to a parent.

I'm not sure I'm following, though.

@waelsaad
Copy link
Author

Thank you @drmohundro for the response.

To provide more context, I'm working on parsing numerous XML documents with intricate nested structures, some referencing external XML files. My goal is to render these XML documents into HTML while preserving the exact node sequence as per the XML structure.

After my initial query, I managed to use the children property to render nodes in the correct XML sequence. However, I foresee a potential issue where a nested node might need knowledge of its parent type for custom logic.

Currently, when deserializing each node from the XMLIndexer, I map it to a custom enum XMLNode to identify its type. I've attempted passing the parent type during deserialization, but I'm uncertain if I executed this correctly.

In my perspective, it would be ideal for an XMLIndexer node to have access to its parent node, similar to Swift's view.subviews or view.parent in the context of views.

    public var children: [XMLIndexer] {
        childElements.map { XMLIndexer($0) }
    } 

Here is a sample render function that uses the Plot framework.

		func render(_ node: XMLNode) {
			switch node {
			case let .document(document):
				document?.children.forEach { render($0) }
			case let .title(title):
				if let title = title { nodes.append(HTML.Title(title: title)) }
			case let .text(text):
				if let text = text { nodes.append(HTML.Text(text: text)) }
		}

In my render method above, I believe it would be much clearer for me to have access to the parent node. For instance:

I think it would be much cleaner for me in the render method to do the following:-

			case let .title(title):
				if let title = title {
					if title.parent != .section {
						nodes.append(HTML.Title(title: title))
					}
				}

I hope this proposal to the library makes sense. Thank you :).

@waelsaad
Copy link
Author

waelsaad commented Oct 28, 2023

Actually a parent and or also a full path to the node would be useful. i.e so a title node nested within a section its path would be like "Document/Section/Title" or something like that If you know what I mean

	struct Title: HashedNode {
		var parent: NodeType
		var languages: [LanguageNode]
		let children: [XMLNode]

		static func deserialize(_ node: XMLIndexer) throws -> Title {
			Title(
				parent: try node.element. // not sure if its possible to set parent here.
				languages: try node["Language"].value(),
				children: try node.children.map { try XMLNode.deserialize($0) }
			)
		}
	}

@drmohundro
Copy link
Owner

Yes, I think that makes sense... both about the parent property as well as the path. Let me take some time to see if what it might take to add a feature like that.

@drmohundro
Copy link
Owner

Hi @waelsaad - any way you could check out my branch at https://github.com/drmohundro/SWXMLHash/tree/feat/add-parent-to-xmlelement and see if it might work for you? I don't have "path" support yet, but it should be doable, though I might want to add that as a separate feature. The parent support seems to be pretty straightforward, though I only have a super simple test at the moment.

@drmohundro drmohundro changed the title Decerlized XML Object - How to get parent node Deserialized XML Object - How to get parent node Nov 1, 2023
@waelsaad
Copy link
Author

waelsaad commented Nov 8, 2023

Thank you @drmohundro much appreciated.

@waelsaad
Copy link
Author

waelsaad commented Nov 8, 2023

@drmohundro Apology for a delayed response. Is there a way I can add this specific branch to SPM? so I can access the new added property?

@drmohundro
Copy link
Owner

It looks like SPM does support branch-based targets... something like:

dependencies: [
    .package(url: "https://github.com/drmohundro/SWXMLHash.git", .branch("feat/add-parent-to-xmlelement"))
]

I think this should work.

@drmohundro
Copy link
Owner

Just following up... did the above work for you and were you able to see if it met your expectations?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants