So my query was working fine and I now need to verify the resulting .xml with a .dtd validation. My .xq looked like this before:
< root>
...
...
< /root>
Now it looks like this:
< !DOCTYPE root SYSTEM 'validation.dtd'>
< root>
...
...
< /root>
Running the .xq now, however, throws the following error:
XPST0003 XQuery syntax error near #...as xs:integer external; < !D#:
Expected '--' or '[CDATA[' after '< !'
Static error(s) in query
I don't know what this error means, and I'm unable to find how to fix it
Thanks in advance
To serialize an XML document with a document type declaration, use the fn:serialize() function with the doctype-system parameter:
xquery version "3.1";
fn:serialize(<root/>, map { "doctype-system": "validation.dtd" })
This produces the following string:
<!DOCTYPE root SYSTEM "validation.dtd">
<root/>
For more on this technique, see the function documentation for fn:serialize() at https://www.w3.org/TR/xpath-functions-31/#func-serialize and description of the doctype-system and doctype-public parameters in the XSLT and XQuery Serialization 3.1 Specification at https://www.w3.org/TR/xslt-xquery-serialization-31/#XML_DOCTYPE.
For processors that only support XPath 3.0 or that have not yet implemented the map(*) method of specifying serialization parameters, you can use this form:
xquery version "3.0";
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
fn:serialize(
<root/>,
<output:serialization-parameters>
<output:doctype-system value="validation.dtd"/>
</output:serialization-parameters>
)
I am using Roxy to manage my project. Also using MarkLogic 8.0-6.1
I am trying to submit a searchTerm, and return a custom formatted search:snippet
Here are the complete steps that I am taking:
./../roxy/ml new test-app --server-version=8 --app-type=rest
Configure my build.properties
cd test-app/
./ml local bootstrap
Now I have my project Structure.
Create File - test-app/rest-api/ext/show-search.xqy
xquery version "1.0-ml";
module namespace ss = "http://marklogic.com/rest-api/resource/show-search";
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";
declare
function ss:get(
$context as map:map,
$params as map:map
) as document-node()*
{
map:put($context, "output-types", "application/json"),
map:put($context, "output-status", (200, "OK")),
let $search-term := map:get($params, "searchTerm")
let $query := search:search($search-term,
<options xmlns="http://marklogic.com/appservices/search">
<transform-results apply="raw"/>
</options>
)
return document {$query}
};
(:
:)
declare
function ss:put(
$context as map:map,
$params as map:map,
$input as document-node()*
) as document-node()?
{
map:put($context, "output-types", "application/xml"),
map:put($context, "output-status", (201, "Created")),
document { "PUT called on the ext service extension" }
};
(:
:)
declare
function ss:post(
$context as map:map,
$params as map:map,
$input as document-node()*
) as document-node()*
{
map:put($context, "output-types", "application/xml"),
map:put($context, "output-status", (201, "Created")),
document { "POST called on the ext service extension" }
};
(:
:)
declare
function ss:delete(
$context as map:map,
$params as map:map
) as document-node()?
{
map:put($context, "output-types", "application/xml"),
map:put($context, "output-status", (200, "OK")),
document { "DELETE called on the ext service extension" }
};
The above GET request uses the transform-results apply=raw option, deploys, and functions properly (I have some test documents).
However I do not want to return the whole document, I want to return a whole section of the json that had a match, no matter where in that seciton the match happened (lower levels)
So I try to write my own snipper
Create File - test-app/rest-api/ext/show-search-snipper.xqy
xquery version "1.0-ml";
module namespace sss = "http://marklogic.com/rest-api/resource/show-search-snipper";
import module namespace search = "http://marklogic.com/appservices/search" at "/MarkLogic/appservices/search/search.xqy";
import module namespace json = "http://marklogic.com/xdmp/json" at "/MarkLogic/json/json.xqy";
declare
function sss:my-snippet(
$result as node(),
$ctsquery as schema-element(cts:query),
$options as element(search:transform-results)?
) as element(search:snippet)
{
<search:snippet>
</search:snippet>
};
I then update the search:search call to the following
let $query := search:search($search-term,
<options xmlns="http://marklogic.com/appservices/search">
<transform-results apply="my-snippet" ns="http://marklogic.com/rest-api/resource/show-search-snipper" at="show-search-snipper.xqy"/>
</options>
)
Now I should have everything I need (I think)
I run the deploy ./ml local deploy rest
and get the following
Minty-linux test-app # ./ml local deploy rest Loading REST properties
in /opt/this-is-a-test/test-app/rest-api/config/properties.xml Loading
REST options in /opt/this-is-a-test/test-app/rest-api/config/options
Loading REST extensions from /opt/this-is-a-test/test-app/rest-api/ext
ERROR: 400 "Bad Request" ERROR: {"errorResponse":{"statusCode":400,
"status":"Bad Request", "messageCode":"RESTAPI-INVALIDCONTENT",
"message":"RESTAPI-INVALIDCONTENT: (err:FOER0000) Invalid content:
invalid show-search-snipper extension: show-search-snipper either is
not a valid module or does not provide extension functions (delete,
get, put, post) in the
http://marklogic.com/rest-api/resource/show-search-snipper
namespace"}}
So I tried moving the show-search-snipper.xqy file up 1 level (to test-app/rest-api/show-search-snipper.xqy`
Run the deployment
Deployment Works No errors
Hit the URL and receive the following
500 Internal Server Error
INTERNAL ERROR
RESTAPI-INVALIDREQ: (err:FOER0000) Invalid request: reason: Extension
show-search does not exist. . See the MarkLogic server error log for
further detail.
Although I know the extension was created properly, since it worked fine before the introduction of the custom snip function. (with apply="raw")
Any thoughts how I can apply my custom snip function or what I am doing wrong in deployment?
Should you decide to stick with a custom snippeter:
It looks like Roxy is trying to treat it your snippeter module as a resource extension, which it is not. Your snippeter should be just a vanilla module in the modules db.
IDK how to configure Roxy, unfortunately, but what you're aiming for is to get Roxy to either install it using PUT /v1/ext/directories/asset or a straight up insert (`PUT /v1/documents) on your modules db. See http://docs.marklogic.com/REST/PUT/v1/ext/[directories]/[asset].
Assuming Roxy uses /ext, then the path to your snippeter would NOT be the unqualified path you have in your options. It would be an absolute path rooted at /ext/. See http://docs.marklogic.com/guide/rest-dev/search#id_72390.
There's a simpler way -- you can do this with the extract-document-data search option.
I set up some sample data to work with like this:
xquery version "1.0-ml";
for $i in (1 to 10)
return
xdmp:document-insert(
'/test-content-' || $i || '.json',
xdmp:unquote('{ "important": { "foo": 1, "bar": 2 }, "not-important": { "stuff": 3, "blah": 4 } }')
)
Having bootstrapped and deployed modules, I can get search results at http://localhost:8040/v1/search. However, I can start taking more control of the search results by using stored search options. Take a look in your project at rest-api/config/options/all.xml. They were already deployed for you when you run ml local deploy modules, so you now can search using http://localhost:8040/v1/search?options=all. Since you're using JSON data, I took it one step further and ran with: http://localhost:8040/v1/search?format=json&options=all.
I added this to rest-api/config/options/all.xml:
<extract-document-data selected="include">
<extract-path>/important</extract-path>
</extract-document-data>
This tells the search options to include the specified path with all search results. After deploying and running the search again, one result looks like this:
{
"index":1,
"uri":"/test-content-6.json",
"path":"fn:doc(\"/test-content-6.json\")",
"score":0,
"confidence":0,
"fitness":0,
"href":"/v1/documents?uri=%2Ftest-content-6.json",
"mimetype":"application/json",
"format":"json",
"matches":[{"path":"fn:doc(\"/test-content-6.json\")/object-node()", "match-text":[]}],
"extracted":{
"kind":"array",
"content":[
{"important":{"foo":1, "bar":2}}
]
}
},
Notice the "extracted" part at the end there -- I get the "important" JSON property, as specified in the options.
For a full list of options you can set to control search, see the Query Options Reference appendix.
I get an "xls" response from an webservice. Unfortunately the service only return this format. I would like to parse this file as xml or json. I use the framework symfony. Exist any bundle for handling XLS files, which would you recommend?
Or can i solve this issue with flat PHP?
Update
The xls response look like so, here can i show the first few linse:
<?xml version="1.0" encoding="UTF-8"?>
<xls:XLS xmlns:xls="http://www.opengis.net/xls" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" version="1.1" xsi:schemaLocation="http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/RouteService.xsd">
<xls:ResponseHeader xsi:type="xls:ResponseHeaderType" sessionID="unknown"/>
<xls:Response xsi:type="xls:ResponseType" requestID="unknown" version="1.1" numberOfResponses="1">
<xls:DetermineRouteResponse xsi:type="xls:DetermineRouteResponseType">
<xls:RouteSummary>
<xls:TotalTime>PT22M7S</xls:TotalTime>
<xls:TotalDistance uom="KM" value="33.7"/>
<xls:BoundingBox srsName="EPSG:4326">
<gml:pos>7.8854063 49.9412442</gml:pos>
<gml:pos>8.2769550 50.0041191</gml:pos>
</xls:BoundingBox>
</xls:RouteSummary>
......
If i try to parse the response with "simplexml_load_string" the function return only the following output.
class SimpleXMLElement#1341 (1) {
public $#attributes =>
array(1) {
'version' =>
string(3) "1.1"
}
}
The function shows me only the version and not the child nodes. How can i access the child nodes?
I try to access the child with this syntax:
$xml = simplexml_load_string($response);
var_dump($xml->children('xls', true)->Response->numberOfResponses);
But without any success.
Solved
Now i solved my issue.
$xml = simplexml_load_string($response);
echo $xml->children('http://www.opengis.net/xls')->Response->DetermineRouteResponse->RouteSummary->TotalTime;
So I've got this code that is running fine (I'm using gulp not grunt for what it matters) :
var handlebars = require('handlebars'),
rename = require('gulp-rename'),
map = require('vinyl-map');
gulp.task('test', function(){
return gulp.src(config.path.template+"/*.handlebars")
.pipe(map(function(contents) {
return handlebars.precompile(contents.toString());
}))
.pipe(rename({ extname: '.js' }))
.pipe(gulp.dest(config.path.template+"/test"))
});
Everything runs perfectly, the .js files generate in the good folder, but I need them to generate without the -s parameter. For an example, when I run handlebars path/to/my/hbs.handlebars -f path/to/my/out/folder.js -s (or --simple), the file generated is the same. But I need this command to run without the -s parameter, and I can't find a way to pass this argument in my gulpfile. I tried alot of things, in a String, in a Json, in an array, tried to go with -s false, with simple false, with isSimple false (something I found in handlebars code).
None of this is working and I really need to pass the -s parameter to false. I assume that I need to do something like :
[...]
return handlebars.precompile(contents.toString(), options);
[...]
But I can't find the proper syntax or way to use these options. And that is my problem.
PS : I use this instead of gulp-handlebars so that I can use the version of handlebars I want to use and not another.
EDIT
Searching in handlebars.js code, I just found that options is an object, but I can't find what he's filled with as I'm not a good javascript user.
It seems to me there's no such switch in the source.
Taken from the precompiler source used from the command line tool:
if (opts.simple) {
output.push(Handlebars.precompile(data, options) + '\n');
} else if (opts.partial) {
if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
output.push('return ');
}
output.push('Handlebars.partials[\'' + template + '\'] = template(' + Handlebars.precompile(data, options) + ');\n');
} else {
if (opts.amd && (opts.templates.length == 1 && !fs.statSync(opts.templates[0]).isDirectory())) {
output.push('return ');
}
output.push('templates[\'' + template + '\'] = template(' + Handlebars.precompile(data, options) + ');\n');
}
opts is what you passed in, another variable options is passed to precompile. The decoration is added by the command line tool.
There's a second block with closing brackets a few lines below in the script.
You best copy that source to your code or maybe access the .cli object in your gulp script.
public function preUpload()
{
if (null !== $this->file) {
$this->path = $this->file->guessExtension();
}
}
This doesn't work for .docx files.
I get a file stored under the name "myfile." -> no extension.
How to handle this?
I think you must use:
getClientOriginalExtension()
because you want to get the extension of the original name not the temporary name that the file has in your server.
http://api.symfony.com/2.4/Symfony/Component/HttpFoundation/File/UploadedFile.html
use
getExtension()
as a fallback?
Symfony API
I found a bug in symfony core files where It was missing a mimeType for the .xls files.
We had the same behaviour: GuessExtension would return null.
My team and I narrowed it down to an array which lists symfony's mime types.
Here is a link to the same solution I answered on another question:
https://stackoverflow.com/a/36435844/3980097
You will find the exact path to MimeTypeExtensionGuesse.php
In your case, the missing mime Type might be:
'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx',
I hope this helps!