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

Add method to make a deep copy of all matches #185

Open
Nordiii opened this issue Apr 4, 2023 · 8 comments
Open

Add method to make a deep copy of all matches #185

Nordiii opened this issue Apr 4, 2023 · 8 comments

Comments

@Nordiii
Copy link

Nordiii commented Apr 4, 2023

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
@lukaseder
Copy link
Member

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?

@Nordiii
Copy link
Author

Nordiii commented Apr 4, 2023

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.

@lukaseder
Copy link
Member

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.

@Nordiii
Copy link
Author

Nordiii commented Apr 4, 2023

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.

@lukaseder
Copy link
Member

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.

@Nordiii
Copy link
Author

Nordiii commented Apr 4, 2023

My Problem with your example is that you grab a single match and duplicate it.
In my example I want too:

  1. 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
  2. Make a deep copy of all matches
  3. Replace Placeholders
  4. Insert the batch of matches
  5. remove the original matches with the placeholders from the DOM

Sorry for bothering you, the help is much appreciated!

@lukaseder
Copy link
Member

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?

@Nordiii
Copy link
Author

Nordiii commented Apr 20, 2023

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.

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

No branches or pull requests

2 participants