001package ball.util.ant.taskdefs;
002/*-
003 * ##########################################################################
004 * Utilities
005 * %%
006 * Copyright (C) 2008 - 2022 Allen D. Ball
007 * %%
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *      http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 * ##########################################################################
020 */
021import ball.xml.XalanConstants;
022import java.io.ByteArrayOutputStream;
023import java.io.File;
024import javax.xml.namespace.QName;
025import javax.xml.parsers.DocumentBuilderFactory;
026import javax.xml.transform.Transformer;
027import javax.xml.transform.TransformerFactory;
028import javax.xml.transform.dom.DOMSource;
029import javax.xml.transform.stream.StreamResult;
030import javax.xml.xpath.XPathConstants;
031import javax.xml.xpath.XPathExpression;
032import javax.xml.xpath.XPathFactory;
033import lombok.Getter;
034import lombok.NoArgsConstructor;
035import lombok.Setter;
036import lombok.ToString;
037import lombok.experimental.Accessors;
038import org.apache.tools.ant.BuildException;
039import org.apache.tools.ant.Task;
040import org.apache.tools.ant.util.ClasspathUtils;
041import org.w3c.dom.Document;
042import org.w3c.dom.NodeList;
043
044import static javax.xml.transform.OutputKeys.INDENT;
045import static javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION;
046
047/**
048 * {@link.uri http://ant.apache.org/ Ant} {@link Task} to test
049 * {@link javax.xml.xpath.XPath} expressions.
050 *
051 * {@ant.task}
052 *
053 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
054 */
055@AntTask("xpath-evaluate")
056@NoArgsConstructor @ToString
057public class XPathEvaluateTask extends Task implements AnnotatedAntTask, ClasspathDelegateAntTask,
058                                                       ConfigurableAntTask, XalanConstants {
059    @Getter @Setter @Accessors(chain = true, fluent = true)
060    private ClasspathUtils.Delegate delegate = null;
061    @NotNull @Getter @Setter
062    private File file = null;
063    @NotNull @Getter @Setter
064    private String expression = null;
065    @NotNull @Getter
066    private QName qname = XPathConstants.STRING;
067    @NotNull @Getter @Setter
068    private int tab = 2;
069
070    public void setQname(String name) throws IllegalArgumentException {
071        try {
072            qname = (QName) XPathConstants.class.getField(name.toUpperCase()).get(null);
073        } catch (Exception exception) {
074            qname = QName.valueOf(name);
075        }
076    }
077
078    @Override
079    public void init() throws BuildException {
080        super.init();
081        ClasspathDelegateAntTask.super.init();
082        ConfigurableAntTask.super.init();
083    }
084
085    @Override
086    public void execute() throws BuildException {
087        super.execute();
088        AnnotatedAntTask.super.execute();
089
090        try {
091            log(String.valueOf(getFile()));
092
093            Document document =
094                DocumentBuilderFactory.newInstance()
095                .newDocumentBuilder()
096                .parse(getFile());
097
098            log(getExpression());
099
100            XPathExpression expression = XPathFactory.newInstance().newXPath().compile(getExpression());
101            QName qname = getQname();
102            Object value = expression.evaluate(document, qname);
103
104            if (XPathConstants.NODESET.equals(qname)) {
105                Transformer transformer = TransformerFactory.newInstance().newTransformer();
106
107                transformer.setOutputProperty(OMIT_XML_DECLARATION, YES);
108                transformer.setOutputProperty(INDENT, (tab > 0) ? YES : NO);
109                transformer.setOutputProperty(XALAN_INDENT_AMOUNT.toString(), String.valueOf(tab));
110
111                NodeList nodeset = (NodeList) value;
112
113                for (int i = 0; i < nodeset.getLength(); i += 1) {
114                    ByteArrayOutputStream out = new ByteArrayOutputStream();
115
116                    transformer.transform(new DOMSource(nodeset.item(i)), new StreamResult(out));
117                    log(out.toString("UTF-8"));
118                }
119            } else {
120                log(String.valueOf(value));
121            }
122        } catch (BuildException exception) {
123            throw exception;
124        } catch (RuntimeException exception) {
125            throw exception;
126        } catch (Exception exception) {
127            throw new BuildException(exception);
128        }
129    }
130}