Lisa Anne
Lisa Anne

Reputation: 4595

Android: validate xml file at compile time?

I need to create a custom XML file to be used in my Android application,

the file will contain some custom objects that are needed in my app,

I understand that the I need to put them in the res\xml or res\raw. OK.


Now, I would like to be notified at compile time if something is wrong in the XLM:

for example:

suppose I want to define cats via XML:

<cats>
    <siamese-cat
        fur="short"
        tail="5" />

    <persian-cat
        fur="short"
        tail="5" />
</cats>

I would like to know if it is possible to get a compile time warning if i do something like this:

(where barking is not something I have defined my cats can do):

 <cats>
    <persian-cat
        barks="true"
        fur="short"
        tail="5" />
</cats>

Is that possible?

Please how can I achieve it?

Upvotes: 8

Views: 1699

Answers (3)

s.d
s.d

Reputation: 29436

The following will work on the gradle build system.

First, define an Xml Schema (XSD) document that specifies exactly what should be the structure of XML document. For example, in a file test.xsd:

<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'>
    <xs:element name="animals">
        <xs:complexType>
            <xs:sequence minOccurs="0">
                <xs:element name="animal">
                    <xs:complexType>
                        <xs:attribute name="name" type="xs:string"/>
                        <xs:attribute name="age" type="xs:int"/>
                        <xs:attribute name="sound" type="xs:string"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

In above example, XSD document specifies that we can have only <animal> tags with only 3 attributes: name, age and sound. Also data types of those attributes have been strictly defined. If you are unacquainted to XML schemas, you can read up some online documentation.

Next, create an XML document that is supposed to follow above schema, by referring to to text.xsd as its schema. For example, in a file test.xml:

<?xml version="1.0" encoding="UTF-8"?>
<animals xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:noNamespaceSchemaLocation='test.xsd'>
    <animal name="kitty" age="2" sound="meow"/>
    <cat name="bad_cat"></cat>
</animals>

As you can see, we have deliberately added a tag <cat>, which is not there in the schema definition we just defined.

If you are using Android Studio, it will automatically lookup the schema file and provide auto-complete, as well as highlight schema errors when editing the XML file.

But the purpose is to validate the XML document with XSD schema, every time Gradle builds the android project. So, we define a custom Gradle task to do this. For example, in build.gradle:

import javax.xml.XMLConstants
import javax.xml.transform.stream.StreamSource
import javax.xml.validation.SchemaFactory

task validateXml {
    File xml = new File('./test.xml');
    File xsd = new File('./test.xsd');

    def factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    def schema = factory.newSchema(xsd);
    def validator = schema.newValidator();
    validator.validate(new StreamSource(xml));
}

Here we are using Java XML API to write some groovy code that reads both files and validates the XML file using XSD file. You can now run this task from Gradle CLI:

For example:

./gradlew validateXml

It will fail, with the error:

A problem occurred evaluating root project 'Bad Cats'.
> cvc-complex-type.2.4.d: Invalid content was found starting with element 'cat'. No child element is expected at this point.

Great. Now we want the validateXml task to run every time the project is built. More specifically, when files are packaged. So, we add one more line to Gradle build file (after defining validateXml task):

assemble.dependsOn validateXml;

Now, assemble task will call validateXml automatically on build.

In future, you can just update the XSD file to apply new rules for the XML file.

Upvotes: 5

GhostCat
GhostCat

Reputation: 140525

Suggestion: turn to unit tests for that.

You can create production code that checks the integrity of your XML (for example by running a parser; including schema validation); then you just run that code within certain unit tests. (obviously it is a bit more complicated like that; you have to carefully study what makes the most sense for you; but well, we do something similar; and it turns out to be extremely helpful).

Not exactly "compile time", but close - as many IDEs allow you to run certain unit tests upon changing certain files. And of course, your unit tests will then be part of your unit test regression.

Upvotes: 1

Veaceslav Gaidarji
Veaceslav Gaidarji

Reputation: 4311

Android Lint custom rules to the rescue. You can create your custom lint rule, as described here, and run checks before every build. If something will be wrong with your custom XML file - you'll be notified in the console.

Upvotes: 1

Related Questions