Does eXist-db compression:zip function add XML declaration - xquery

I have an XQuery function to convert a group of XML files to HTML and Zip them. It runs a trasform on each file to create <entry> elements.
Starting with that function:
declare function xport:make-sources( $path as xs:string) as item()* {
for $article in collection(xmldb:encode-uri($path))
let $docnum := $article/article/div[#class = 'content']/#doc/string()
return
<entry name="{concat($docnum,'.html')}" type='text' method='store'>
{transform:transform($article, doc("/db/EIDO/data/edit/xsl/doc-html.xsl"), <parameters/>)}
</entry>
} ;
Given the input, I run the XQuery to just show me the result of the transformation ... and I see this (exactly what I would expect):
<entry name="LS01.html" type="text" method="store">
<html>
<head>
<style>
body {
font-family: Arial;
}
article img {
width:50%;
}
...
You will note the this entry and all of them have no XML Declaration at all.
But now let's put it all together and send those entries to compression. This is all inside a web application. The full XQuery is this:
xquery version "3.0";
import module namespace transform = "http://exist-db.org/xquery/transform";
declare namespace xport = "http://www.xportability.com";
declare function xport:make-sources( $path as xs:string) as item()* {
for $article in collection(xmldb:encode-uri($path))
let $docnum := $article/article/div[#class = 'content']/#doc/string()
return
<entry name="{concat($docnum,'.html')}" type='text' method='store'>
{transform:transform($article, doc("/db/EIDO/data/edit/xsl/doc-html.xsl"), <parameters/>)}
</entry>
} ;
let $path := request:get-parameter("path", "")
let $filename := request:get-parameter("filename", "")
let $col := xport:make-sources($path)
return
response:stream-binary(
xs:base64Binary(compression:zip($col,true()) ),
'application/zip',
$filename
)
Everything works, I get a ZIP file of all the documents that have been transformed to HTML from the XML.
BUT, when I look at the actually file in the ZIP, it has this:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<head>
The XML Declaration is not on any of the entries to ZIP. It does not exist anywhere (as it couldn't) in the list of entries. But the action of zipping them apparently is adding the declaration. I see no other reason or way. Even specifying omit-xml-declaration or changing the output type in the XSL to text or HTML makes no difference. And this is of course, because the entry list to zip is shown above and that shows the declaration is not there after the transformation.
The files in the ZIP have an added XML declaration, period.
Is there some workaround?

The XML declaration is introduced implicitly in your query when the contents of your zip-bound <entry> elements are passed to the compression:zip() function. I'd advise setting serialization options explicitly using the fn:serialize() function. Here is sample code showing how to achieve the result you describe:
xquery version "3.1";
let $node := <html><head/><body><div><h1>Hello World!</h1></div></body></html>
let $serialized := serialize($node, map { "method": "xml", "indent": true(),
"omit-xml-declaration": true() })
let $entries := <entry name="test.html" type="text" method="store">{$serialized}</entry>
let $filename := "test.zip"
return
response:stream-binary(
compression:zip($entries, true()),
'application/zip',
$filename
)
Saving this query into the database at a location like /db/apps/my-app/test.xq and calling it by pointing your web browser at http://localhost:8080/exist/apps/my-app/test.xq will cause your browser to download test.zip. Opening this zip file will reveal a test.html file absent the XML declaration:
<html>
<head/>
<body>
<div>
<h1>Hello World!</h1>
</div>
</body>
</html>
Stepping back to the fundamentals, the presence or absence of the XML declaration in XQuery is toggled via the omit-xml-declaration serialization parameter. To omit the XML declaration globally for an entire query, you can place this set of declarations in the prolog of your query:
declare namespace output="http://www.w3.org/2010/xslt-xquery-serialization";
declare option output:method "xml";
declare option output:omit-xml-declaration "yes";
Or, when serializing locally within a portion of a query, you can pass this same set of parameters to the fn:serialize function as a map (the method used in the code sample above):
fn:serialize($node, map { "method": "xml", "omit-xml-declaration": true() } )
(There is also an XML syntax for the 2nd options parameter.)
The current version of eXist (v4.0.0) and recent versions (probably since v3.6.0 or so) support all of the options above, and all versions support a somewhat more compact eXist-specific serialization facility, using the exist:serialize option expressed as a string consisting of key=value pairs:
declare option exist:serialize "method=xml omit-xml-declaration=yes";
You can set eXist's default serialization behavior in your conf.xml configuration file. The defaults in conf.xml can be overridden with the methods above. Serialization behavior over different interfaces in eXist, such as WebDAV or XML-RPC, typically respect the defaults set in conf.xml, but these defaults can be overridden on a per-interface basis; for example, see the documentation on serialization over eXist's WebDAV interface.

Related

This block contains invalid or unexpected content on Custom HTML

I am editing a document in draft mode Wordpress 5.2.2 in the Gutenberg editor, and add this Custom HTML block:
<pre><code class="language-typescript">const simple = &ltT&gt(cl: T) => cl;
class Hero {
constructor(public position: [number, number]) {}
}
interface { hello: number }
const errorOne = &ltT&gt(cl: T) => new cl(); // Cannot use 'new' with an expression whose type lacks a call or construct signature.</code></pre>
and it happily works as expected in preview. I save as draft.
When I return the HTML is ghosted and I get the error in the title. I can convert to HTML and it works again, but then it errors again when I return to it later.
It seems this error is talked about everywhere but the explanations are nonsense and resolve nothing.
If my Custom HTML is valid (which it seems to be), why does it work and then give an error. How do I fix this?
I think the main issue is not converting < & > properly in your code. They are missing the semicolon at the end of the string.
This code is working fine:
<pre><code class="language-typescript">const simple = <T>(cl: T) => cl;
class Hero {
constructor(public position: [number, number]) {}
}
interface { hello: number }
const errorOne = <T>(cl: T) => new cl(); // Cannot use 'new' with an expression whose type lacks a call or construct signature.</code></pre>
When you insert the code with missing semicolon, WordPress saved as is. However, when trying the load the page again WordPress compares the saved content (with missing characters) to the one generated from the block (which is probably attempting to display correct HTML). This process led to an error as both texts were not identical.
If you want to check the error yourself you can check the console through developer tool in your browser (F12 in Chrome).

How to write Content Transformations using xquery in marklogic?

I have a javascript function(.sjs) which will return a string.
Now, I've to write a xquery transformation which will be triggered through dmsdk. Xquery function will accept a json doc, inside this transformation i need to trigger that javascript function which will return a string. Now, I need to use that string as a uri to load documents..
I've no idea on xquery!!
myXquery transformation function(jsonDoc)
{
/////////////////
myJavaScript function- which return a string
load the doc using this string as uri
}
Use Below query:
declare namespace local ="local";
declare function local:transformation($json-input, $json-uri as xs:string)
{
xdmp:save(concat("D:\", $json-uri), $json-input)(:Here I saved file on local path, If you want to save on Marklogic-DB use-: xdmp:document-insert( $json-uri, $json-input) :)
};
(:1:)
let $input := '{"menu":{"id":"file", "value":"File"}}'
for $json-input in $input
(:2 Call here your Javascript function for json-uri :)
let $json-uri :="json_first.json"
return local:transformation(xdmp:unquote($json-input), $json-uri)

I don't understand JSON and when I'm supposed to use it, care to explain?

I just started learning ASP.NET and I came across Web Services. I don't fully understand what purpose does JSON serves, when am I supposed to use it, and why is it better than XML. Care to explain please?
JSON is a text-based object serialization format that's more lightweight than XML. It directly integrates with JavaScript's object model. That's most of its advantages right there.
You would primarily use JSON to send data between a web client and a web server, often times using WebServices. It serializes arrays and objects into human readable text and can easily be parsed by a computer. It is the ECMA 404 standard.
Here is an example of a JSON serialized class with some properties, with one of the properties being an array:
{firstname: 'Joe', lastname: 'Smith', phonenumbers: ['555-555-5555','444-444-4444']}
Also JSON in many cases is more lightweight to work with than XML, due to it's simple format. I would, if you not already feel you are familiar with arrays, functions and objects in JavaScript- take a look at it. After that JSON will feel very familiar and easy to work with
JSON is syntax for storing and exchanging text information - much like XML.
It's main advatages over XML are:
is smaller and shorter than XML
faster and easier to parse,
quicker to read and write
from W3schools, JSON object could look like this:
var employees = [
{ "firstName":"John" , "lastName":"Doe" },
{ "firstName":"Anna" , "lastName":"Smith" },
{ "firstName":"Peter" , "lastName": "Jones" }
];
XML file could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<employees >
<employee>
<firstName>John</firstName>
<lastName>Doe</lastName>
</employee>
<employee>
<firstName>Anna</firstName>
<lastName>Smith</lastName>
</employee>
<employee>
<firstName>Peter</firstName>
<lastName>Jones</lastName>
</employee>
</employees >
From the above examples you should see it is much faster to read and write JSON object rather than XML, because it is much smaller and shorter.
When you want to do some data exchange between the server and web browser and dynamically load some data - for example from a database, JSON object is extremely handy:
function yourJavascriptfunction(sender){
$.post("returndata.php", {
UserID:sender.name
})
.success(function(data){
var returnedObject = JSON.parse(data);
for(var i = 0; i < returnedObject.Data.length; i++){
console.log(returnedObject.Data[i]["someRowInYourTable"]);
}
})
.fail(function(jqXHR, textStatus, errorThrown){
alert("Unable to retrieve data from the server, error code:" + errorThrown);
});
}
and your php file called returndata.php could return for example these data from your created database
<?php
$connection = mysqli_connect("localhost","root","password","yourDatabase") or die(mysql_error());
$userID = $_POST['UserID'];
$query1 = mysqli_query($connection, "SELECT * FROM table1 WHERE userid = $userID");
$returnObject = new stdClass();
$returnObject->Error = "Some error";
$ObjectArray = array();
$position = 0;
while ($newrow = mysqli_fetch_array($query1)) {
$ObjectArray[$position] = $newrow;
$position++;
}
$returnObject->Data = $ObjectArray;
echo json_encode($returnObject);
?>
There are indeed some differences...
Advantages of XML:
Supports Comments
Supports namespaces
Supports schemas
Advantages of JSON:
Smaller
Natively supports null
Native object support
Native array support
Provides scalar datatypes (strings are strings and numbers are numbers, etc.). Lacking with dates though.
Simpler (but matter of opinion)
Readability... Some argue that XML is harder to read... I disagree. For hierarchical data, XML can shine. JSON can look like gibberish if you are not used it, especially if it's not formatted and indented. I think it's a draw in this case.

Very confused about how to parse xml with namespace prefixes

So, I need to be able to parse xml files that could include namespace prefixes. I've tried doing this with a sample file and it gives me back null when trying to get a nodelist, even when I specify a node that has no attribute prefixes.
I've been trying to research this and it keeps coming back to the fact that without the namespace prefix defined, it won't work, so I've added code that I thought would do this, but it's still giving the same results. Here's some code I've added:
protected void Page_Load(object sender, EventArgs e)
{
xml.Load(Server.MapPath("~/SomeLesson/imsmanifest.xml"));
populateBaseNodes();
}
private void populateBaseNodes()
{
treeViewMenu.Nodes.Clear(); // Clear any existing items
TreeNode treenode = new TreeNode();
treenode.Text = "organizations";
XmlNodeList baseNodeList;
string xmlns = xml.DocumentElement.Attributes["xmlns"].Value;
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
nsmgr.AddNamespace("adlcp", "http://www.adlnet.org/xsd/adlcp_v1p3");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("imscp", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("imsss", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
baseNodeList = xml.SelectNodes("/manifest/organizations/organization/item", nsmgr);
TextBox1.Text = baseNodeList.Count.ToString();
foreach (XmlNode xmlnode in baseNodeList)
{
TreeNode treeNodeCatalog = new TreeNode();
treeNodeCatalog.Text = xmlnode.Attributes["identifier"].Value;
treeNodeCatalog.SelectAction = TreeNodeSelectAction.Expand;
treeViewMenu.Nodes.Add(treeNodeCatalog);
}
treeViewMenu.CollapseAll();
}
(marc_s) Here's the XML in question that needs to be parsed:
<manifest identifier="Navigating_in_QuickBooks_-_Introduction_MANIFEST" version="1.3"
xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:imscp="http://www.imsglobal.org/xsd/imscp_v1p1"
xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3"
xmlns:imsss="http://www.imsglobal.org/xsd/imsss"
xsi:schemaLocation=" http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd
http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd
http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd
http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd
http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd">
<metadata>
<!-- not relevant here ... -->
</metadata>
<organizations default="TOC1">
<organization identifier="TOC1">
<title>Navigating in QuickBooks - Introductory Lesson</title>
<item identifier="I_SCO0" identifierref="SCO0">
<title>Navigating in QuickBooks - Introductory Lesson</title>
</item>
</organization>
</organizations>
<resources>
<!-- not relevant here ... -->
</resources>
</manifest>
You're not showing us what your XML looks like - but two comments:
you don't need to add the xsi prefix, and I'm not sure what the schemaLocation prefix is supposed to do ....
when you've defined the schema prefixes, you also need to use those prefixes in your XPath, of course!
Again, not knowing what your XML structure looks like, I cannot really tell what you need - but something along the lines of:
baseNodeList = xml.SelectNodes("/adlcp:manifest/adlcp:organizations/adlcp:organization/imscp:item", nsmgr);
or whatever other XML namespace prefixes your source XML requires.
Update: seeing your XML makes it clearer: see the root node - it has a default XML namespace (the one with xmlns="...." and no explicit prefix):
<manifest identifier="Navigating_in_QuickBooks_-_Introduction_MANIFEST" version="1.3"
xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" <=== DEFAULT namespace!!!
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:imscp="http://www.imsglobal.org/xsd/imscp_v1p1"
xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3"
xmlns:imsss="http://www.imsglobal.org/xsd/imsss"
................>
That means: ALL your subsequent nodes that don't have a specific XML prefix will be in that default namespace.
Unfortunately, .NET XML parsing has problem with defining a default namespace without prefix - so my best solution is to create a namespace with a prefix for the default namespace, and then use it:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xml.NameTable);
// add default namespace, with a prefix for .NET
nsmgr.AddNamespace("ns", "http://www.imsglobal.org/xsd/imscp_v1p1");
baseNodeList =
xml.SelectNodes("/ns:manifest/ns:organizations/ns:organization/ns:item", nsmgr);
Do you get any results now??
In the XML you posted the default namespace controlling all of the elements in your sample file is:
xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
This namespace does not define a prefix so you must add this namespace to your namespace manager using a blank prefix. I think you should be able to use this code to define the default namespace (using String.Empty to specify a blank prefix):
nsmgr.AddNamespace(String.Empty, "http://www.imsglobal.org/xsd/imscp_v1p1");

How to get server side variable value in xsl template?

I want use localized strings from resources in xsl template as in aspx page, like this:
<%=GetLocalizedString("grid_numberof_claim")%>. I am trying use
<xsl:text disable-output-escaping="yes">
<![CDATA[<%=GetLocalizedString("grid_numberof_claim")%>]]>
</xsl:text>
but it is not useful.
Actually i can pass localized strings inside XML node, for example "localization". But i am looking for way to get its value in aspx style.
Using ASPX style isn't possible.
You can use XsltArgumentList to send parameters to your XSLT template, as explained here: HOW TO: Execute Parameterized XSL Transformations in .NET Applications
EDIT: Yes, you can pass arguments client-side too.
xmldoc = ... // your xml document
var xslt = new ActiveXObject("Msxml2.XSLTemplate.4.0");
var xslDoc = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.4.0");
xslDoc.async = false;
xslDoc.load("YourTemplate.xsl");
xslt.stylesheet = xslDoc;
xslProc = xslt.createProcessor();
xslProc.input = xmldoc;
xslProc.addParameter("param1", 123);
xslProc.addParameter("param2", "abc");
xslProc.transform();
But client-side leads to another solution: You can rename your XSLT file to ASPX and to use <%= %> syntax

Resources