1

How do I format this expression so that when a for-loop is running it only selects where analysis attributes are empty. The reason is that there are multiple templateNames with the same values. This is my attempt but can't get to work

String theXpath = "//report-plan[@name='"+ templateName +"']/settings/@analysis=''";

Sample code:

public class XPathTestReports {
    public static void main(String[] args) {
        try {
            String outputFile = "c:/workspace/samplenew.xml";
            String inputFile = "c:/workspace/sample.xml";

            Document doc = DocumentBuilderFactory.newInstance()
            .newDocumentBuilder().parse(new InputSource(inputFile));

            // locate the node(s)
            XPath xpath = XPathFactory.newInstance().newXPath();

            // lOAD THE File
            CSVImporterReports loader = new CSVImporterReports("C:/REPORT_TEMPLATES.csv");
            List < OnConfig > entries = loader.getEntries();

            for (OnConfig c: entries) {
                String templateName = c.getTemplateName();
                String analName = c.getAnalysisName();
                String paramName = c.getParamName();
                String theXpath = "//report-plan[@name='" + templateName + "']/settings/@analysis=''";
                NodeList nodes = (NodeList) xpath.evaluate(theXpath, doc, XPathConstants.NODESET);

                // make the change
                for (int i = 0; i < nodes.getLength(); i++) {
                    nodes.item(i).setTextContent(analName);
                    // nodes.item(i).setTextContent(paramName);
                }
            }

            try {
                // save the result
                Transformer xformer = TransformerFactory.newInstance().newTransformer();
                xformer.transform(new DOMSource(doc), new StreamResult(new File(outputFile)));
            } catch (TransformerConfigurationException e) {
                // TODO Auto-generated catch block
            } catch (TransformerFactoryConfigurationError e) {
                // TODO Auto-generated catch block
            } catch (TransformerException e) {
                // TODO Auto-generated catch block
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (XPathExpressionException e) {
            e.printStackTrace();
        }
    }
}

Sample XML:

<report-plan name="generic">
              <columns>
                <column name="Nominal" subtotal-function="Sum" total-function="Sum"/>
                <column name="Trade"/>
              </columns>
              <settings analysis="" analysisParameters="" filtering-enabled="true" object-actions="false" show-object-actions="true" sorting-enabled="true"/>
</report-plan>
<report-plan name="generic">
              <columns>
                <column name="Nominal" subtotal-function="Sum" total-function="Sum"/>
                <column name="Trade"/>
              </columns>
              <settings analysis="" analysisParameters="" filtering-enabled="true" object-actions="false" show-object-actions="true" sorting-enabled="true"/>
</report-plan>
<report-plan name="sensitive">
              <columns>
                <column name="Nominal" subtotal-function="Sum" total-function="Sum"/>
                <column name="Trade"/>
              </columns>
              <settings analysis="" analysisParameters="" filtering-enabled="true" object-actions="false" show-object-actions="true" sorting-enabled="true"/>
</report-plan>

At the moment my code is inputting the same value for both reports named generic. Even though the analysis attributes have different values to be entered. I need the code to enter in different analysis values even if the report names are the same.

Output:

<report-plan name="generic">
              <columns>
                <column name="Nominal" subtotal-function="Sum" total-function="Sum"/>
                <column name="Trade"/>
              </columns>
              <settings analysis="newValue" analysisParameters="" filtering-enabled="true" object-actions="false" show-object-actions="true" sorting-enabled="true"/>
</report-plan>
<report-plan name="generic">
              <columns>
                <column name="Nominal" subtotal-function="Sum" total-function="Sum"/>
                <column name="Trade"/>
              </columns>
              <settings analysis="newValue" analysisParameters="" filtering-enabled="true" object-actions="false" show-object-actions="true" sorting-enabled="true"/>
</report-plan>
<report-plan name="sensitive">
              <columns>
                <column name="Nominal" subtotal-function="Sum" total-function="Sum"/>
                <column name="Trade"/>
              </columns>
              <settings analysis="someValue" analysisParameters="" filtering-enabled="true" object-actions="false" show-object-actions="true" sorting-enabled="true"/>
</report-plan>

CSV sample

TEMPLATE_NAME   ANALYSIS_NAME   PARAM_NAME
generic         analval1        paramval1
generic         analval2        paramval2
sensitivity     analval3        paramval3
5
  • What's wrong with your current xpath? Commented Apr 30, 2015 at 13:22
  • 1
    Only select what exactly if the analysis attribute is empty? Commented Apr 30, 2015 at 13:23
  • Only select that analysis attribute within that report-plan element. There are multiple report plan elements some of which have values and others are empty so I am only selecting the ones that are empty. Updated to show related code. Commented Apr 30, 2015 at 13:33
  • 1
    What is the point of selecting empty attributes? You know what they contain anyway. Also, please show an input document - and show what exactly the output should look like. Commented Apr 30, 2015 at 13:42
  • I have two reports when the same names but when it is adding in the values it is adding the same value for both even though it should be different. Added XML sample to show. Commented Apr 30, 2015 at 14:52

2 Answers 2

3

Okay, I think I see what you're going for here. You want to use XPath to give you the @analysis nodes that exist and are empty, so that you can fill them in with some configured value.

String theXpath = "//report-plan[@name='" + templateName + "']/settings/@analysis[.='']";

EDITED TO ADD:

Now, keep in mind that this will select ALL the @analysis nodes for the template name. When you do the second-level for loop, you are changing ALL of them. On the next CSV called "generic", it will find no nodes left to change.

Replace:

for (int i = 0; i < nodes.getLength(); i++) {
    nodes.item(i).setTextContent(analName);
}

with:

if (nodes.getLength() > 0) {
    nodes.item(0).setTextContent(analName);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes correct. However this expression does not work as the analysis attribute is still being configured with a duplicate value for templates with the same name. My code should read the next row of the csv containing a same templateName but containing a different value for the analysis attribute that should be configered.
1

Maybe you mean something like

String theXpath = "//report-plan[@name='"+ templateName +"' and not(settings/@analysis > '')]";

This selects all <report-plan> elements with a certain name and no settings/@analysis (or an empty one).

2 Comments

this is not what I'm looking to do. Updated my question to explain further
@Kelv I think this is what you are looking for. For each selected <report-plan> element you can to its <settings> child go an set the analysis attribute.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.