I am currently trying to write an app (a game) that will, I hope, run on both desktop and Android. The data format I have chosen to use is XML because it's more flexible and powerful than JSON, it performs better than a database and I am familiar with it and like it.
However, I'm beginning to wonder if it's going to actually be possible to use XML.
In addition to plain old XML I'm also using XInclude in my data structures and XPath to locate the relevant nodes. This seems to require that I also validate my XML during parse, which is fine because I had already written the XML Schema when developing the XML in the first place.
I've managed to get everything working on the desktop, however, as soon as I tried to run it on Android it failed. It seems that the XML parser used by default on Android doesn't support XInclude (source).
I've added the following line to my build.gradle:
compile "xerces:xercesImpl:2.12.0"
and it seems to have worked in that the SchemaFactory seems to be resolving to the Xerces one as evidenced by the debugging output:
08-21 14:19:35.488 8254-8332 W/System.err: JAXP: Reading jar:file:/data/app/uk.co.redfruit.gdx.wobbegong-geDT8AfzN-vHBlDA-lE0_g==/base.apk!/META-INF/services/javax.xml.validation.SchemaFactory
JAXP: instantiating org.apache.xerces.jaxp.validation.XMLSchemaFactory
But the DocumentBuilderFactory appears to be using the default Android one because it still throws the error:
java.lang.UnsupportedOperationException: This parser does not support specification "Unknown" version "0.0"
Which is what is always thrown when you call setXIncludeAware on the DocumentBuilderFactory (See above link).
I had assumed that including it in my gradle build file would do the trick and it seems like it partly has, but not enough.
I'm hoping that all crosss platform XML parsing problems will be solved by using the same parser implementation on all platforms, but it doesn't seem as straight forward as that...
Take a look at the javadocs for DocumentBuilderFactory.newInstance()
Use the javax.xml.parsers.DocumentBuilderFactory system property.
I suggest you set the javax.xml.parsers.DocumentBuilderFactory system property to the classname of the xerces DocumentBuilderFactory implementation
I'm guessing it's this is the class you want
eg:
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
doFunkyXmlStuff();
To specify the parser to be used as Xerces-2, I would suggest to pass the parser classname when instantiating the DocumentBuilderFactory as follows:
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance("org.apache.xerces.jaxp.DocumentBuilderFactoryImpl", null);
docFactory.setXIncludeAware(true);
Related
I need to dynamically load a xml layout from the server. LayoutInflater has inflate methods that use a XmlPullParser. I've tried that, but it doesn't work.
Looking into the Android source code, it turns out those inflate methods are called with a XmlResourceParser. The implementation Android uses is XmlBlock.Parser, but that is not a public API.
Is there a XmlResourceParser public implementation I can use?
You can use a traditional XmlPullParser like described in Android documentation :
InputStream yourRemoteLayout = ...;
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(yourRemoteLayout, "someEncoding");
AttributeSet attributes = Xml.asAttributeSet(parser);
Please see what's explained in XmlPullParser documentation for more details.
Edit : From LayoutInflater#inflate() documentation :
Important For performance reasons, view inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
What I guess, is that maybe you should make your own implementation of LayoutInflater.Factory2 if Android's own only rely on preprocessed resources.
in fact, you CAN NOT load xml layout dynamically. android system DOES NOT need a XmlResourceParser. when android ui system inflate an resource, it just convert the parser to it's private implementation, a binary xml source parser (i forgot the class name).
1 year ago, i tried this, spent many many times. so, don't waste your time as me again.
YES, right now is possible with ItsNat Droid.
Take a look to this summary:
https://groups.google.com/forum/#!topic/itsnat/13nl0P12J_s
It is still under heavy development but most important features are already implemented.
For performance reasons, view inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
That isn't to say it can't be done. But you will need to run the build tools on the xml file to get it into the right format. Then you can probably mock a 'Context' and 'Resources' that returns the downloaded data when used in a 'LayoutInflator'
I am trying to read XML->POCO using an xsd, so I use the Xsd2Code generator, giving me a simple Xml Serializer code. When I dry-test this in the regular Windows world, with my XML I have no issues getting around 18 POCOs from the xml-file.
The fun begins in the Android world. I see that the loading of the XML file is done perfect, no issues there I have a perfectly sound XML string. When the Deserialization is complete I only get the first element in the xml file, missing 17 POCOs.
What is wrong here? Is the Xml Serializer/Deserializer working diffrently in Mono?
I guess you should find a reduced testcase (simple program) that works on .NET and fails in MonoDroid, and attach it to a new bug in http://bugzilla.xamarin.com/
Hello all my second question here so be gentle :)
I'm still learning java and android, I'm learning it on my little project but I hit kind of logical wall.
I have XML file
<shift_plan>
<plan>
<agent data="John Smith"/>
<date data="6 Jan"/>
<shift data="M-3"/>
</plan>
<plan>
<agent data="John Smith"/>
<date data="7 Jan"/>
<shift data="M-3"/>
</plan>
<plan>
<agent data="John Smith"/>
<date data="8 Jan"/>
<shift data="M-3"/>
</plan>
</shift_plan>
on a web and I want to make a loop that would paste each data to function that put it to db. I have the function and working db so it looks like updateBD(agent, date, shift ) but how would I go about parsing the xml but to parse the 3 variables than put them in that function and than go again for the next 3 etc...until end of xml
I might be not making much sense I know, this must be something very simple I'm sure but I need really kick in the right direction..
Thanks for any answer,
Vlad
Android supports the XmlPullParser API right out of the box. It is an excellent solution for parsing XML documents in Android apps because you can start pulling information from the document right away (it's a streaming XML parser) and its pull-style API is a lot easier to use than that of a push-style streaming XML parser when all you need to do is parse the document into objects.
I am not sure if this is still true in Android 3 and 4, but the Android 2.3.x and earlier implementation of XmlPullParser (from the Apache Harmony project) does not support getPrefix() or getAttributePrefix(int index). Though, this shouldn't affect you because you are not using XML namespaces.
EDIT: Examining the git trees corresponding to the platform_frameworks_base tags, it appears that Android 3.2.4 and earlier have the XmlPullParser implementation from the Harmony project whereas beginning with Android 4.0, the implementation switched to kXML2.
I cant find anything about it.
I just want to find if a specific row exist in my DOM xml object (and more efficiently then going through all nodes).
In order to do that I need an ID attribute and in order to set an attribute as an ID so I could use getElementById I need to set a schema on my DocumentBuilderFactory.
So.. I built an XSD file in a pretty random spot in my resurces (folder called xml) - is there a standard place to put it in?
and I tried something like this:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Source schemaSource = new StreamSource(getClass().getResourceAsStream("online_list_schema.xsd"));
Schema mySchema;
mySchema = factory.newSchema(schemaSource);
dbf.setSchema(mySchema);
yes , I don't really know how to use getResourceAsStream .. (why does it asks for a Sting and not for Int?)
but lets start with the fact that
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
generates an error even if its by its own..
12-05 10:00:27.879: E/AndroidRuntime(996): Caused by:
java.lang.IllegalArgumentException: http://www.w3.org/2001/XMLSchema
so my questions are:
where should I put an xml schema in my resources (or- should I put
xml schema in my resources if not what should I do?)
why does SchemaFactory.newInstance gives me an error and how do I
use it correctly
how to load the schema source from my resources and are the other
lines in the code correct?
I need to get data from an XML file in Android. On the iPhone environment, my code is:
NSURL *thisURL = [[NSURL alloc] initWithString:#"http://www.xxx.com/file.xml"];
NSArray *myArray = [[NSArray alloc] initWithContentsOfURL:providerURL];
myArray is now an array of dictionary items initialized with contents from file.xml.
Is there any way to do this in Android? Can someone point me to doc or sample code?
I'm new to the Android environment and just need some direction.
Thanks,
Kevin
See Working with XML in Android for a variety of methods for dealing with XML. Which method to use depends on how big your XML is, and what you want to do with it. '
I'm not sure how it makes any sense to turn XML into an array, so no, none of the methods do that. If you want something similar to that, use Json instead of XML.
After a bit of research, it appears to me that using the Simple XML Serialization framework is going to be my best bet, especially since I do have a relatively simple XML file to read. The result will be a 'list' class with several 'entry' classes which seems like a viable way to handle this...probably better than having an array of classes as was done in the iPhone app.