Add method to make a deep copy of all matches
My Usecase
I want to modify .fodt Files and replace the placeholders inside the document with values from a Database.
Now I gather multiple matches via the nextUntil(Filter) Method. Currently I need to do something like this to deep copy all elements:
List<ProjectDTO> projects;
Match projectMatches = aMatch.nextUntil(filter);
projects.stream().forEach(project -> {
List<Element> deepCopies = projectMatches.each()
.stream().map(val -> (Element) val.get(0).cloneNode(true))
.toList();
Match copy = $();
copy = copy.add((deepCopies.toArray(new Element[deepCopies.size()])));
//Do Stuff with the copy
});
There is Probably a cleaner way, but it would be nice if I could just call projectMatches.deepCopy()
Versions:
- jOOX:2.0.0
- Java:17
Another workaround is to just toString() the matches and import them again. But I'm not sure if I understand the connection between your use-case and your suggested solution. Can you describe your use-case instead?
Sorry for me beeing unclear! I have an office document in .fodt format (XML) which works as a template, now I need to fill placeholder values with data from the database. Some placeholders should be duplicated, in case there are multiple values stored in the database. Lets say there are 3 Projects (name, time and more data stored in the database). Now the office document has a section for a Project with placeholders which should be replaced.
This bit could look like this in the fodt File:
....
<text:p>$PROJECT_START<\text:p>
<text:p><text:span>$PROJECT_NAME</text:span><\text:p>
<table:table>
<table:row>
...
</table:row>
</table:table>
...
</text:p>$PROJECT_END</text:p>
...
Now I gather all matches via nextUntil(matches("$PROJECT_END")). All values between the placeholder "$PROJECT_START" and "$PROJECT_END" are collected by this.
All matches gathered I want to duplicate those 3 times (for each Project) and fill the placeholders with the project specific data.
Some placeholders should be duplicated, in case there are multiple values stored in the database.
Ah, I see. I was thinking of replacing placeholders, not duplicating them.
Anyway, this should work?
Match d = JOOX.$("""
<a>
<b/>
</a>
""");
d.append(d.find("b").toString());
System.out.println(d);
I can see the utility of making this available through API, but in most cases, the string workaround is good enough.
Copying multiple matches (without inserting them in the existing DOM?) sadly does throw an error:
projects.stream().forEach(project -> {
Match copy = $(projectMatches.toString());
//Do Stuff with the copy
});
Error: org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted.
EDIT: Calling
projects.stream().forEach(project -> {
Match copy = $().append(projectMatches.toString());
//Do Stuff with the copy
});
does not throw an error but is an empty copy.
But you're not doing what I suggested, you're doing entirely other things. $(String) creates a new document, and that has to be valid, which it isn't in the first case. In the second case, there is no root element, so nothing can be added.
My Problem with your example is that you grab a single match and duplicate it. In my example I want too:
- Grab a batch of matches (nextUntil()) (I can’t go by an single XML Tag to get a root node for the project because the next parent is the whole text document, which contains not only the project data) Then for each project
- Make a deep copy of all matches
- Replace Placeholders
- Insert the batch of matches
- remove the original matches with the placeholders from the DOM
Sorry for bothering you, the help is much appreciated!
If you have an "xmlforest", just add a new dummy root node:
Match:
<a/>
<a/>
<a/>
String workaround:
<dummy>
<a/>
<a/>
<a/>
</dummy>
I mean, it's a workaround. There are other tricks, too. You could also loop over each element in the match using each() and do element-by-element processing.
I hope this helps?
Sorry for the late reply, thank you a lot for the help and time you provided! Thanks to you I was able to archive my goal.