2

I'm trying to create a new xml with a structure and at the same time add elements via this

String styleName = "myStyle";
String styleKey = "styleKeyValue";

File file = new File("test.xml");        

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document document = builder.newDocument();

Match x = $(document)
                .namespace("s", "http://www.mycompany.com/data")
                .append(
                    $("Data",
                        $("Styles",
                            $("Style",
                                $("Attributes", "")
                            ).attr("name", styleName)
                        )
                    )
                );

Match xpath = x.xpath("//s:Attributes");

xpath = xpath.append($("Attribute", "").attr("key", styleKey));

x.write(file);

However .append doesn't seem to add anything and I end up with an empty file.
This approach is based on this SO answer but the "Document document = $(file).document();" line gives me an exception as the file doesn't exist - hence the use of DocumentBuilder.

Of course I realise that I can create new xml file through a host of other means I am trying to stick with Joox based approach at the moment.

Dazed
  • 1,069
  • 9
  • 34

2 Answers2

3

Working version after feedback from Lucas Eder (Joox "all the way" option)

// Initial block to create xml structure
Match x = $("Data",
             $("Styles",
                $("Style",
                    $("Attributes", "")                                            
                 ).attr("name", styleName)
              )
           ).attr("xmlns", "http://www.mycompany.com/data");

// example xpath into structure to add element attribues
// as required
Match xpath = x.xpath("//Attributes");

xpath = xpath.append($("Attribute", "").attr("key", styleKey));

x.write(file);

Produces the following:

<Data xmlns="http://www.mycompany.com/data">
    <Styles>
        <Style name="myStyle">
            <Attributes>
                <Attribute key="styleKeyValue"/>
            </Attributes>
        </Style>
    </Styles>
</Data>
Dazed
  • 1,069
  • 9
  • 34
1

The problem here is a misunderstanding of what Match.append() does. Let's look at it this way

The Javadoc reads:

Append content to the end of each element's content in the set of matched elements.

Now, if you do this:

Match x = $(document);

This just wraps an existing document in a jOOX Match wrapper for further processing. This Match wrapper matches no elements at all, because there are no elements in the wrapped document, not even a root element (you created a new one). So, in order to actually create a document with elements, you have to:

  • Either create the root element using the DOM API
  • Or use jOOX all the way, as can be seen below:

    Match x = $("Data",
                $("Styles",
                  $("Style",
                    $("Attributes", "")
                   ).attr("name", styleName)
                 )
               );
    

Note that your Match.namespace() call does not have the effect you'd like it to have. There is currently no way to set a namespace on jOOX-generated elements. This is the pending feature request for this feature: https://github.com/jOOQ/jOOX/issues/133

The Match.namespace() method simply binds a namespace to a prefix in the match context, for subsequent xpath() calls. Here's the Javadoc extract of the method:

Get a new Match with added namespace configuration for subsequent XPath calls

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • Ok thanks - I understand. I guess I was expecting a failed match to throw an Exception. I realise I could have used "if (x.isEmpty())" but that would impede the method chaining style. I have revised my code along the lines (joox all the way option) you suggest and got it working - will add as an edit to the question.. – Dazed Jun 10 '17 at 17:38
  • @Dazed: Great idea, btw you can provide your own answer here on stack overflow. It's the recommended way to suggest your final solution, rather than editing the question for that... – Lukas Eder Jun 11 '17 at 19:02