How to Parse XML File using xmlparsing on iphone? - iphone

How do I access following XML file using xmlparsing on an iphone?
<?xml version="1.0" encoding="iso-8859-1"?>
<chapter>
<TITLE>Title &plainEntity;</TITLE>
<para>
<informaltable>
<tgroup cols="3">
<tbody>
<row><entry>a1</entry><entry morerows="1">b1</entry><entry>c1</entry></row>
<row><entry>a2<<?xml version="1.0" encoding="iso-8859-1"?>
<ADDRESS>
<CONTACT>
<NAME FIRST="Fred" LAST="Bloggs" NICK="Bloggsie" TITLE="Mr" />
<STREET HOME="5 Any Street" WORK="Floor 24, BigShot Tower" />
<CITY HOME="Little Town" WORK="Anycity" />
<COUNTY HOME="Anyshire" WORK="Anyshire" />
<POSTAL HOME="as plain text" WORK="text" />
<COUNTRY HOME="UK" WORK="UK" />
<PHONE HOME="as text" WORK="text" />
<FAX HOME="none" WORK="555" />
<MOBILE HOME="444" WORK="333" />
<WEB HOME="www.codehelp.co.uk" WORK="" />
<COMPANY>Full name of company here</COMPANY>
<GENDER>male</GENDER>
<BDAY>Add tags for year, month and day to make this more useful</BDAY>
<ANNI>some date long forgotten :-)</ANNI>
<SPOUSE>angry</SPOUSE>
<CHILDREN>Make sure this tag is one of the ones allowed to repeat in the DTD</CHILDREN>
<COMMENT>comments here</COMMENT>
<EMAILONE>Either use fixed tags like this, or change to a repeating tag</EMAILONE>
<EMAILTWO>second email line</EMAILTWO>
<EMAILTHREE>third</EMAILTHREE>
<EMAILFOUR>fourth</EMAILFOUR>
</CONTACT>
</ADDRESS>/entry><entry>c2</entry></row>
<row><entry>a3</entry><entry>b3</entry><entry>c3</entry></row>
</tbody>
</tgroup>
</informaltable>
</para>
&systemEntity;
<section id="about">
<title>About this Document</title>
<para>
<!-- this is a comment -->
</para>
</section>
</chapter>

The SDK provides two ways to parse XML: libxml2 and NSXMLParser. libxml2 is the fastest. To use it in your project, go to the build settings for your iPhone App project and set the following:
Other linker flags = -lxml2
Header Search Paths: $(SDKROOT)/usr/include/libxml2
Then download XPathQuery.m and XPathQuery.h from this page: Using libxml2 for XML parsing and XPath queries in Cocoa, which also provides a tutorial on how to use it. That XPathQuery class is a simplified way to parse XML. I recommend it unless you want to write the same code yourself, which doesn't seem the case.
With that on place, do
NSString *string = nil; // put your html document here
NSData *htmlData = [string dataUsingEncoding:NSUTF8StringEncoding];
NSString *xpath = #"//row"; // any standard XPath expression
NSArray *nodesArray = PerformHTMLXPathQuery(htmlData, xpath);
NSDictionary *dict;
if (0<[nodesArray count]) {
dict = [nodesArray objectAtIndex:0];
}
At this point the elements from your document should be inside the dict dictionary.

Here are releated the SO post,
Parser XML with NSXMLParser
http://www.raywenderlich.com/553/how-to-chose-the-best-xml-parser-for-your-iphone-project
NSXMLParser example
below is the blog tutorial for using NSXMLParser.
http://markstruzinski.com/?p=47

Related

SWXMLHash can't parse a [XMLIndexer]

I am trying for first time to parse a XML file and I am using SWXMLHash.
My xml file is:
<weatherdata xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://api.met.no/weatherapi/locationforecast/1.9/schema" created="2018-02-13T18:12:31Z">
<meta>
<model name="LOCAL" termin="2018-02-13T12:00:00Z" runended="2018-02-13T14:27:32Z" nextrun="2018-02-13T22:00:00Z" from="2018-02-13T19:00:00Z" to="2018-02-16T06:00:00Z" />
<model name="EPS" termin="2018-02-13T00:00:00Z" runended="2018-02-13T09:03:05Z" nextrun="2018-02-13T22:00:00Z" from="2018-02-16T12:00:00Z" to="2018-02-22T18:00:00Z" />
</meta>
<product class="pointData">
<time datatype="forecast" from="2018-02-13T19:00:00Z" to="2018-02-13T19:00:00Z">
<location altitude="0" latitude="" longitude="">
<temperature id="TTT" unit="celsius" value="3.5"/>
<windDirection id="dd" deg="158.8" name="S"/>
<windSpeed id="ff" mps="8.8" beaufort="5" name="Frisk bris"/>
<windGust id="ff_gust" mps="15.0"/>
<areaMaxWindSpeed mps="13.8"/>
<humidity value="82.1" unit="percent"/>
<pressure id="pr" unit="hPa" value="1002.5"/>
<cloudiness id="NN" percent="99.3"/>
<fog id="FOG" percent="0.0"/>
<lowClouds id="LOW" percent="73.2"/>
<mediumClouds id="MEDIUM" percent="0.0"/>
<highClouds id="HIGH" percent="91.0"/>
<dewpointTemperature id="TD" unit="celsius" value="0.6"/>
</location>
</time>
The <time> </time> repeates.
Having made a let parsedResultXML = SWXMLHash.parse(data)
I am trying to parse with a for in loop
for node in parsedResultXML["weatherdata"]["product"]["time"].all{
print(node)
}
I get results
<time to="2018-02-14T01:00:00Z" from="2018-02-14T01:00:00Z" datatype="forecast">
<location latitude="" longitude="" altitude="0">
<temperature id="TTT" unit="celsius" value="3.4"></temperature>
<windDirection id="dd" name="S" deg="158.7"></windDirection>
<windSpeed name="Liten kuling" mps="11.1" id="ff" beaufort="6"></windSpeed>
<windGust id="ff_gust" mps="19.0"></windGust>
<areaMaxWindSpeed mps="17.5"></areaMaxWindSpeed>
<humidity unit="percent" value="88.3"></humidity>
<pressure id="pr" unit="hPa" value="1002.5"></pressure>
<cloudiness id="NN" percent="99.3"></cloudiness>
<fog id="FOG" percent="0.1"></fog>
<lowClouds id="LOW" percent="98.6"></lowClouds>
<mediumClouds id="MEDIUM" percent="93.4"></mediumClouds>
<highClouds id="HIGH" percent="57.8"></highClouds>
<dewpointTemperature id="TD" unit="celsius" value="1.5"></dewpointTemperature>
</location>
</time>
But I can't access the elements.
Using
for node in parsedResultXML["weatherdata"]["product"]["time"].all{
node["time"].element?.attribute(by: "from")?.text
}
I don't get any results back.
Any idea??
Thanks
You're close... as #rmaddy commented, node is already indexed to "time". So instead of:
for node in parsedResultXML["weatherdata"]["product"]["time"].all {
node["time"].element?.attribute(by: "from")?.text
}
Do this instead:
for node in parsedResultXML["weatherdata"]["product"]["time"].all {
node.element?.attribute(by: "from")?.text
}

DocuSign API not asking or setting the dateSigned though it is present in the xml

Having followed the example found earlier here on StackOverflow (dateSignedTabs does not work), I still fail to get a signature date to appear. Here's a snippet of the xml.
<?xml version="1.0" encoding="UTF-8"?>
<envelopeDefinition xmlns="http://www.docusign.com/restapi">
<emailSubject>Boiler Contract -00006)</emailSubject>
<status>sent</status>
<documents>
<document>
<documentId>1</documentId>
<name>VDBK SW6-CSIK-0001.pdf</name>
</document>
</documents>
<recipients>
<signers>
<signer>
<recipientId>1</recipientId>
<routingOrder>1</routingOrder>
<note>Team</note>
<email>joebloggs#gmail.com</email>
<name>Eric Test6-1</name>
<tabs>
<signHereTabs>
<signHere>
<xPosition>58</xPosition>
<yPosition>617</yPosition>
<documentId>1</documentId>
<pageNumber>1</pageNumber>
</signHere>
</signHereTabs>
<dateSignedTabs>
<dateSigned>
<xPosition>58</xPosition>
<yPosition>440</yPosition>
<tabLabel>Date Signed</tabLabel>
<name>Date Signed</name>
<documentId>1</documentId>
<pageNumber>1</pageNumber>
<recipientId>1</recipientId>
</dateSigned>
</dateSignedTabs>
</tabs>
</signer>
</signers>
</recipients>
</envelopeDefinition>
Can anybody spot why this is off?

Orbeon control details in own component

I'm making my own component, and I want to have oportunity to set some properties in form builder. In all I want to reach effect similar to autocomplete control, where I can set 3 properties (URI, xpath, and relative xpath). I read, that I can do it using control-details markup, but unfortunately it does not work. This is code (I working on davinci tutorial):
<xbl:binding element="fr|tutorial-davinci" id="fr-tutorial-davinci" xxbl:mode="lhha binding value">
<metadata xmlns="http://orbeon.org/oxf/xml/form-builder" xmlns:xf="http://www.w3.org/2002/xforms">
<display-name lang="en">davinci-modified</display-name>
<templates>
<instance label=""/>
<view>
<fr:tutorial-davinci id="" appearance="minimal" labelref="#label" xmlns="" resource="" >
<xf:label ref=""/>
<xf:hint ref=""/>
<xf:help ref=""/>
<xf:alert ref=""/>
</fr:tutorial-davinci>
</view>
</templates>
<control-details>
<xf:input>
<xf:label lang="en">Some param</xf:label>
</xf:input>
</control-details>
</metadata>
<xbl:template>
<xf:model>
<xf:instance id="id1"><value/></xf:instance>
</xf:model>
<xf:input ref="instance('id1')" />
</xbl:template>
</xbl:binding>
You must have a ref attribute on<xf:input> which points to an attribute or element where the information will be stored. In autocomplete.xml, there is in particular theresource` attribute, which:
is pointed to by <xf:input>
is present on the <fr:autocomplete> template

Orbeon autocomplete - Content is not allowed in prolog

I'm trying to add an autocomplete component in dynamic mode to a form created with the Orbeon Form Builder (version Orbeon Forms 3.9.0+.stable.201109261742 PE).
The xml below is a simple test form with the autocomplete that retrieves the data from a public webservice (currently with a static request body).
The first time the autocomplete loads the data it works just fine: the items are presented in a list. But the second time, when I type another character to narrow down the search results, or when I select an item from the list, I get the error message "Content is not allowed in prolog".
If I ignore the error and continue anyway, the error changes to "Got unexpected request sequence number".
I don't understand why it only works the first time since the data returned by the web service is always the same because of the static request body.
Below you find the complete xml of the test form.
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xforms="http://www.w3.org/2002/xforms"
xmlns:saxon="http://saxon.sf.net/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:exforms="http://www.exforms.org/exf/1-0"
xmlns:sql="http://orbeon.org/oxf/xml/sql"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xhtml:head>
<xhtml:title>Test form</xhtml:title>
<xforms:model id="fr-form-model">
<xforms:instance id="fr-form-instance">
<form>
<section-1>
<codeSearch/>
</section-1>
</form>
</xforms:instance>
<xforms:bind id="fr-form-binds" nodeset="instance('fr-form-instance')">
<xforms:bind id="section-1-bind" nodeset="section-1">
<xforms:bind id="codeSearch-bind" nodeset="codeSearch" name="codeSearch" type="xforms:string"/>
</xforms:bind>
</xforms:bind>
<xforms:instance id="fr-form-metadata" xxforms:readonly="true">
<metadata>
<application-name>IRISbox</application-name>
<form-name>Test</form-name>
<title xml:lang="fr">Test form</title>
<description xml:lang="fr"/>
<author/>
<logo mediatype="" filename="" size=""/>
</metadata>
</xforms:instance>
<xforms:instance id="fr-form-attachments">
<attachments>
<css mediatype="text/css" filename="" size=""/>
<pdf mediatype="application/pdf" filename="" size=""/>
</attachments>
</xforms:instance>
<xforms:instance id="fr-form-resources" xxforms:readonly="false">
<resources>
<resource xml:lang="fr">
<codeSearch>
<label>Cities</label>
<hint/>
<help/>
<alert/>
</codeSearch>
<section-1>
<label>Test</label>
<help/>
</section-1>
</resource>
</resources>
</xforms:instance>
<xforms:instance id="fr-service-request-instance" xxforms:exclude-result-prefixes="#all">
<request/>
</xforms:instance>
<xforms:instance id="fr-service-response-instance" xxforms:exclude-result-prefixes="#all">
<response/>
</xforms:instance>
<!-- Search Cities by Name HTTP service -->
<xforms:instance id="searchCitiesByName-instance" class="fr-service"
xxforms:exclude-result-prefixes="#all">
<body><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.restfulwebservices.net/ServiceContracts/2008/01">
<soapenv:Header/>
<soapenv:Body>
<ns:GetCitiesByCountry>
<ns:Country>USA</ns:Country>
</ns:GetCitiesByCountry>
</soapenv:Body>
</soapenv:Envelope></body>
</xforms:instance>
<xforms:submission id="searchCitiesByName-submission" class="fr-service"
ref="instance('fr-service-request-instance')"
resource="http://www.restfulwebservices.net/wcf/WeatherForecastService.svc"
method="post"
serialization="application/xml"
mediatype="application/soap+xml; action=GetCitiesByCountry"
replace="instance"
instance="searchCitiesByName-instance"/>
<xforms:action ev:event="xforms-submit" ev:observer="searchCitiesByName-submission">
<xxforms:variable name="request-instance-name" select="'searchCitiesByName-instance'"
as="xs:string"/>
<xforms:insert nodeset="instance('fr-service-request-instance')"
origin="saxon:parse(instance($request-instance-name))"/>
</xforms:action>
</xforms:model>
</xhtml:head>
<xhtml:body>
<fr:view>
<xforms:label ref="instance('fr-form-metadata')/title"/>
<fr:body>
<fr:section id="section-1-section" bind="section-1-bind">
<xforms:label ref="$form-resources/section-1/label"/>
<xforms:help ref="$form-resources/section-1/help"/>
<fr:grid columns="1">
<xhtml:tr>
<xhtml:td>
<fr:autocomplete
id="codeSearch"
bind="codeSearch-bind"
dynamic-itemset="true"
max-results-displayed="50">
<xforms:label ref="$form-resources/codeSearch/label"/>
<!-- React to user searching -->
<xforms:action ev:event="fr-search-changed">
<xxforms:variable name="search-value" select="event('fr-search-value')"/>
<xxforms:variable name="make-suggestion" select="string-length($search-value) >= 2"/>
<xforms:action if="$make-suggestion">
<xforms:setvalue ref="instance('code-search-instance')/searchFor" value="$search-value"/>
<xforms:send submission="searchCitiesByName-submission"/>
</xforms:action>
<xforms:action if="not($make-suggestion)">
<!-- Delete itemset -->
<xforms:delete nodeset="instance('searchCitiesByName-instance')//*:GetCitiesByCountryResult/*:string"/>
</xforms:action>
</xforms:action>
<xforms:itemset nodeset="instance('searchCitiesByName-instance')//*:GetCitiesByCountryResult/*:string">
<xforms:label ref="text()"/>
<xforms:value ref="text()"/>
</xforms:itemset>
</fr:autocomplete>
</xhtml:td>
</xhtml:tr>
<xhtml:tr>
<xhtml:td>
<widget:xforms-instance-inspector xmlns:widget="http://orbeon.org/oxf/xml/widget" id="orbeon-xforms-inspector"/>
</xhtml:td>
</xhtml:tr>
</fr:grid>
</fr:section>
</fr:body>
</fr:view>
</xhtml:body>
</xhtml:html>
Any help is appreciated.

How to insert schemalocation in a xml document via DOM

i create a xml document with JAXP and search a way to insert the schemalocation.
At the moment my application produces:
<?xml version="1.0" encoding="UTF-8"?>
<root>
...
</root>
But i need:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="namespaceURL"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="namespaceURL pathToMySchema.xsd">
...
</root>
My code:
StreamResult result = new StreamResult(writer);
Document doc = getDocument();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.METHOD, "xml");
trans.setOutputProperty(OutputKeys.VERSION, "1.0");
trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
DOMSource source = new DOMSource(depl.getAsElement(doc));
trans.transform(source, result);
Thanks for your time,
Kasten
In XML data model namespace nodes are not actually read from parent element but each element has its own namespace nodes. Therefore simply adding a new default namespace to root element doesn't work but results in a document like this
<root xmlns="namespaceURL">
<child xmlns=""/>
...
</root>
Notice the appearing of empty default namespace xmlns="" on the child element(s). What actually needs to be done is to modify the namespace of every node or to create a new document with the desired default namespace and copy the contents, element and attribute names etc. of the old document to the new one. These can be done by recursively going through the original document. With Java DOM implementation this can be laborious, I've heard. One short cut might be to read the document with a namespace-unaware DOM and then add as attribute the new default namespace. Other solution is to change the namespace with an XSLT transformation, which seems quite suitable in this case, since you actually are already generating the output via XSLT transformation.
Use this XSLT stylesheet to add a new default namespace and the schema location to the root element. This stylesheet preserves old namespaces but adds all elements to new default namespace if they previously were in no-namespace.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- Template to add a default namespace to a document -->
<!-- Elements without a namespace are "moved" to default namespace -->
<!-- Elements with a namespace are copied as such -->
<!-- string for default namespace uri and schema location -->
<xsl:variable name="ns" select="'namespaceURL'"/>
<xsl:variable name="schemaLoc" select="'namespaceURL pathToMySchema.xsd'"/>
<!-- template for root element -->
<!-- adds default namespace and schema location -->
<xsl:template match="/*" priority="1">
<xsl:element name="{local-name()}" namespace="{$ns}">
<xsl:attribute name="xsi:schemaLocation"
namespace="http://www.w3.org/2001/XMLSchema-instance">
<xsl:value-of select="$schemaLoc"/>
</xsl:attribute>
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<!--template for elements without a namespace -->
<xsl:template match="*[namespace-uri() = '']">
<xsl:element name="{local-name()}" namespace="{$ns}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<!--template for elements with a namespace -->
<xsl:template match="*[not(namespace-uri() = '')]">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!--template to copy attributes, text, PIs and comments -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Instead of creating the transformer with
Transformer trans = transfac.newTransformer();
(which creates and stylesheet that does an identy transformation), create an XSLT input source and give it as a parameter to newTransformer()
javax.xml.transform.Source xsltSource = new javax.xml.transform.stream.StreamSource(xsltFile);
Transformer trans = transFact.newTransformer(xsltSource);
where xsltFile is a File object pointing to that XSLT file.
Set the output properties as you wish and call transform() as in your sample code. The result should be what you desired, but I have not tested this in Java. The given XSLT file is tested for some trivial cases and there is a sample input and output at the end of this answer.
Some minor notes:
The original document object is not modified in this process. The new default namespace only appears in the output of the transform() method.
The namespace prefix for schema-instance namespace is usually xsi:, not xs: as in your example code (xs: is used in schema definitions (as well as xsd:)) .
Sample input and output for the XSLT stylesheet shown above
Input:
<root>
<child>text</child>
<child attribute="attr-value"/>
<?pi-target pi-content?>
<nsx:ns-child xmlns:nsx="ns1x">
<no-ns-child>text</no-ns-child>
<!-- comment -->
<nsx:ns-child nsx:ns-attribute="nsx-attr-value">text</nsx:ns-child>
</nsx:ns-child>
<defns-child xmlns="default-ns">
<def-child attr="val">text</def-child>
<child xmlns=""/>
</defns-child>
<child>text</child>
</root>
Output:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="namespaceURL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="namespaceURL pathToMySchema.xsd">
<child>text</child>
<child attribute="attr-value"/>
<?pi-target pi-content?>
<nsx:ns-child xmlns:nsx="ns1x">
<no-ns-child>text</no-ns-child>
<!-- comment -->
<nsx:ns-child nsx:ns-attribute="nsx-attr-value">text</nsx:ns-child>
</nsx:ns-child>
<defns-child xmlns="default-ns">
<def-child attr="val">text</def-child>
<child xmlns="namespaceURL"/>
</defns-child>
<child>text</child>
</root>
You can add the namespaces in the root when creating the document.
String NS_URL = "namespaceURL";
doc = builder.newDocument();
Element root = doc.createElementNS(NS_URL, "root");
root.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance",
"xs:schemaLocation", NS_URL + " pathToMySchema.xsd");
doc.appendChild(root);
Then for each element added to the doc instead of createElement() use createElementNS()
doc.createElementNS(NS_URL, name);
This results in what you were looking for.
<root
xmlns="namespaceURL"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="namespaceURL pathToMySchema.xsd"
>
Here's how to give a hint to the parser in order to solve your problem:
http://bytes.com/topic/java/answers/16892-xerces-how-perfrom-schema-validations-without-using-xsi-schemalocation
It goes like this:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(true);
dbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
"http://www.w3.org/2001/XMLSchema");
dbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLocation",
"http://www.example.com/Report.xsd");
Here is a validation example with some source code. It might help you.
http://www.ibm.com/developerworks/xml/library/x-tipvalschm/
(If all comes to worse, you can always search-and-replace. I know it is not the ideal solution, but the javax.xml.transform.OutputKeys doesn't seem to have a member related to the schemalocation attribute.)