tags:

views:

538

answers:

3

I have an XML file of the following form -

<map MAP_XML_VERSION="1.0">
    <entry key="database.user" value="user1"/>
    ...
</map>

Does ant have a native ability to read this and let me perform an xquery to pull back values for keys? Going through the API I did not see such capabilities.

A: 

Sounds like you want something like ant-xpath-task. I'm not aware of a built-in way to do this with Ant.

Yishai
+1  A: 

The optional Ant task XMLTask is designed to do this. Give it an XPath expression and you can select the above into (say) a property. Here's an article on how to use it, with examples. It'll do tons of other XML-related manipulations/querying/creation as well.

e.g.

<xmltask source="map.xml">
   <!-- copies to a property 'user' -->
   <copy path="/map/entry[@key='database.user']/@value" attrValue="true" property="user"/>
</xmltask>

Disclaimer: I'm the author.

Brian Agnew
+2  A: 

You can use the scriptdef tag to create a JavaScript wrapper for your class. Inside JS, you pretty much have the full power of Java and can do any kind of complicated XML parsing you want.

For example:

<project default="build">

    <target name="build">

        <xpath-query query="//entry[@key='database.user']/@value" xmlFile="test.xml" addproperty="value"/>
        <echo message="Value is ${value}"/>

    </target>

    <scriptdef name="xpath-query" language="javascript">
        <attribute name="query"/>
        <attribute name="xmlfile"/>
        <attribute name="addproperty"/>

        <![CDATA[
            importClass(java.io.FileInputStream);
            importClass(javax.xml.xpath.XPath);
            importClass(javax.xml.xpath.XPathConstants);
            importClass(javax.xml.xpath.XPathFactory);
            importClass(org.xml.sax.InputSource);

            var exp = attributes.get("query");
            var filename = attributes.get("xmlfile");
            var input = new InputSource(new FileInputStream(filename));
            var xpath = XPathFactory.newInstance().newXPath();
            var value = xpath.evaluate(exp, input, XPathConstants.STRING);

            self.project.setProperty( attributes.get("addproperty"), value );

        ]]>

    </scriptdef>

</project>
Kevin
So far I definitely like this approach but I am running into an issue. At the evaluate call it hangs for 30-40 seconds, and I get a javax.script.ScriptException wrapping a javax.xml.xpath.XPathExpressionException. I get this even when I simplify the query to select the entire document. Any thoughts?
PHeath
I'd have to see the XML you're working with and the xpath query. The sample above is only designed to select text elements. Its possible that you're trying to select a node or node set.
Kevin
It should be returning the value of the attribute "value" of the element "entry". The xpath query is identical to what you put into the example there. The only thing I neglected to mention was there is a doctype (<!DOCTYPE map SYSTEM "http://java.sun.com/dtd/preferences.dtd">) and the standard xml header at the top.
PHeath
I bet it's trying to resolve the preferences.dtd across the wire.
Brian Agnew
Kudos to you Brian, that's exactly what the problem was. Question resolved.
PHeath
One more question - I've been struggling with trying to create an extension of org.xml.sax.EntityResolver, and I can't figure out the syntax to do so. I need to put in : class MyEntityResolver implements EntityResolver{ public InputSource resolveEntity(String publicId, String systemId){ return new InputSource(new StringReader("")); }}But it complains about "class". Are you allowed to create classes like this in a scriptdef, or do I have to move this out to a java file?
PHeath
I just found "http://www.mozilla.org/rhino/ScriptingJava.html" which should cover what I was looking for.
PHeath