Reputation: 4595
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
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
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
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