Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: validate xml file at compile time?

Tags:

java

android

xml

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?

like image 566
Lisa Anne Avatar asked Jan 05 '16 12:01

Lisa Anne


2 Answers

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.

like image 31
Veaceslav Gaidarji Avatar answered Sep 19 '22 03:09

Veaceslav Gaidarji


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.

like image 103
S.D. Avatar answered Sep 20 '22 03:09

S.D.