Scala xhtml attribute breaks because of a question mark - xhtml

I had a problem with:
<iframe id="iframe1" src='http://stockcharts.com/h-sc/ui?s=MT&p=D&yr=2&mn=0&dy=0&id=p43321191731' width="300px" height="300px"></iframe>
in Lift web framework (Scala) version. I get:
Message: java.util.NoSuchElementException
scala.RandomAccessSeq$$anon$13.next(RandomAccessSeq.scala:165)
scala.xml.parsing.MarkupParser$class.normalizeAttributeValue(MarkupParser.scala:1191)
It turned out the question mark ? in the iframe src attribute that caused this.
What can I do to fix this quickly?

http://www.mail-archive.com/liftweb#googlegroups.com/msg08961.html
The problem is the ampersand, need to escape it
<iframe id="iframe1" src='http://stockcharts.com/h-sc/ui?s=MT&p=D&yr=2&mn=0&dy=0&id=p43321191731' widt h="300px" height="300px"></iframe>

Escape the '&' characters.
scala> <elem attr="a&"/>
res0: scala.xml.Elem = <elem attr="a&"></elem>
Or:
scala> val a = "a&"
a: java.lang.String = a&
scala> <elem attr={a}/>
res1: scala.xml.Elem = <elem attr="a&"></elem>

Related

Saxon xquery validation fails - help needed to understand behavior

Whilst i am using Saxon java api to execute the following xQuery, i am unable to understand why the following execution / validation fails ? (Interestingly , when i replace and clause with or in the if statement, the query validation is successful but am unable to understand this behaviour )
In oxygen xml validator, when i open the xQuery, i get NullPointerException-null exception and the validation fails.
And in java , i get the following area
java.lang.NullPointerException
at net.sf.saxon.expr.parser.LoopLifter.markDependencies(LoopLifter.java:168)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:112)
I am looking up for some experts to help me understand why the following fails.
Following is the xQuery,
declare function local:method($input as element(input)) as element(output)
{
<output>
<itemADetails>
<service>
{
for $i in 1 to count($input/*:foo)
return
for $j in 1 to count($input/*:bar)
return
if((data($input/*:foo[$i]/*:itemB[1]/*:rangeQualifier)="A") and (data($input/*:foo[$i]/*:serviceId/*:type)="B") ) then
<node></node>
else()
}
</service>
</itemADetails>
</output>
};
declare variable $input as element(input) external;
local:method($input)
Saxon Verion
implementation 'net.sf.saxon:Saxon-HE:10.2'
implementation 'net.sf.saxon:saxon-xqj:9.1.0.8'
Sample Snippet that i tried
Processor saxon = new Processor(false);
// compile the query
XQueryCompiler compiler = saxon.newXQueryCompiler();
XQueryExecutable exec;
ClassLoader classLoader = MessageProcessor.class.getClassLoader();
exec = compiler.compile(new File(classLoader.getResource("Xquery.xqy").getFile()));
Source src = new StreamSource(new StringReader(Files.readString( Paths.get(ClassLoader.getSystemResource(inputfile.xml").toURI()))));
XdmNode doc = builder.build(src);
// instantiate the query, bind the input and evaluate
XQueryEvaluator query = exec.load();
query.setContextItem(doc);
query.setExternalVariable(new QName("input"), doc.select(child("input")).asNode());
XdmValue result = query.evaluate();
System.out.println(result.itemAt(0).toString());
Irrespective of the java code when i open the xquery in Oxygen XML editor (that uses Saxon-PE XQuery 9.9.1.7 engine) , i get the following validation error.
It is indeed a Saxon optimisation bug. The problem occurs when Saxon attempts to rewrite
for $j in 1 to count($input/bar)
return if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')
then <result/>
else ()
as
if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')
then for $j in 1 to count($input/bar)
return <result/>
else ()
and you can work around the problem by doing this rewrite "by hand". The purpose of the rewrite is to prevent the unnecessary repeated evaluation of the "if" condition, which is the same each time round the loop.
The reason it's dependent on the "and" condition is that Saxon considers each term of the "and" as a separate candidate for promoting outside the loop, and when it finds that all these terms can be promoted, it reconstitutes the "and" expression from its parts, and the bug occurs during this reconstitution.
It seems like an optimizer bug in Saxon, I reduced your code to
declare function local:test($input as element(input)) as element(output)
{
<output>
<details>
<service>
{
for $i in 1 to count($input/foo)
return
for $j in 1 to count($input/bar)
return if ($input/foo[$i]/data = 'A' and $input/baz[$i]/type = 'B')
then <result/>
else ()
}
</service>
</details>
</output>
};
declare variable $input as element(input) external := <input>
</input>;
local:test($input)
and Saxon HE 10.2 from the command line crashes with
java.lang.NullPointerException
at net.sf.saxon.expr.parser.LoopLifter.markDependencies(LoopLifter.java:168)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:112)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:122)
at net.sf.saxon.expr.parser.LoopLifter.gatherInfo(LoopLifter.java:101)
at net.sf.saxon.expr.parser.LoopLifter.process(LoopLifter.java:51)
at net.sf.saxon.query.XQueryFunction.optimize(XQueryFunction.java:452)
at net.sf.saxon.query.XQueryFunctionLibrary.optimizeGlobalFunctions(XQueryFunctionLibrary.java:327)
at net.sf.saxon.query.QueryModule.optimizeGlobalFunctions(QueryModule.java:1207)
at net.sf.saxon.expr.instruct.Executable.fixupQueryModules(Executable.java:458)
at net.sf.saxon.query.XQueryParser.makeXQueryExpression(XQueryParser.java:177)
at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:568)
at net.sf.saxon.query.StaticQueryContext.compileQuery(StaticQueryContext.java:630)
at net.sf.saxon.s9api.XQueryCompiler.compile(XQueryCompiler.java:609)
at net.sf.saxon.Query.compileQuery(Query.java:804)
at net.sf.saxon.Query.doQuery(Query.java:317)
at net.sf.saxon.Query.main(Query.java:97)
java.lang.NullPointerException
I think on the command line you can turn off optimization with -opt:0, then the above code doesn't crash.
You might want to raise your bug as an issue on https://saxonica.plan.io/projects/saxon/issues or wait until someone from Saxonica picks it up here.
If I use
for $foo at $i in $input/foo
return
for $bar at $j in $input/bar
Saxon doesn't crash, so perhaps that is a way to rewrite your query as a workaround, although, without data, I am not quite sure I have captured the meaning of your code and that rewrite does the same as your original attempt.
I reproduced it with Martin's test case (thank you, Martin): https://saxonica.plan.io/issues/4765

How we can add xpath information in schematron error message output

I am using schematron API in MarkLogic to validate the XML document. Below is the snippet of code for reference.
xquery version "1.0-ml";
import module namespace sch = "http://marklogic.com/validate" at
"/MarkLogic/appservices/utils/validate.xqy";
import module namespace transform = "http://marklogic.com/transform" at "/MarkLogic/appservices/utils/transform.xqy";
declare namespace xsl = "http://www.w3.org/1999/XSL/not-Transform";
declare namespace iso = "http://purl.oclc.org/dsdl/schematron";
let $document :=
document{
<book xmlns="http://docbook.org/ns/docbook">
<title>Some Title</title>
<chapter>
<para>...</para>
</chapter>
</book>
}
let $schema :=
<s:schema xmlns:s="http://purl.oclc.org/dsdl/schematron"
xmlns:db="http://docbook.org/ns/docbook">
<s:ns prefix="db" uri="http://docbook.org/ns/docbook"/>
<s:pattern name="Glossary 'firstterm' type constraint">
<s:rule context="db:chapter">
<s:assert test="db:title">Chapter should contain title</s:assert>
</s:rule>
</s:pattern>
</s:schema>
return
sch:schematron($document, $schema)
Can anyone help me out to get the XPath information of the context node along with schematron error message output.
Here is code for what I think you are asking for.
If you want the xpath of an item you can use xdmp:path. in order to get the xpath of the whole document you'll just have to walk the tree, which is what the recursive function local:getXpathDeep is doing. You can change the formatting of the output from the string-join that I used, it just made it easier to read for me. I created an XML output to put both the schematron results and the XPath into but you can just return a sequence if you like or put it into a map.
xquery version "1.0-ml";
import module namespace sch = "http://marklogic.com/validate" at
"/MarkLogic/appservices/utils/validate.xqy";
import module namespace transform = "http://marklogic.com/transform" at "/MarkLogic/appservices/utils/transform.xqy";
declare namespace xsl = "http://www.w3.org/1999/XSL/not-Transform";
declare namespace iso = "http://purl.oclc.org/dsdl/schematron";
declare function local:getXpathDeep($node){
(
xdmp:path($node),
if (fn:exists($node/*)) then (
local:getXpathDeep($node/*)
) else ()
)
};
let $document :=
document{
<book xmlns="http://docbook.org/ns/docbook">
<title>Some Title</title>
<chapter>
<para>...</para>
</chapter>
</book>
}
let $schema :=
<s:schema xmlns:s="http://purl.oclc.org/dsdl/schematron"
xmlns:db="http://docbook.org/ns/docbook">
<s:ns prefix="db" uri="http://docbook.org/ns/docbook"/>
<s:pattern name="Glossary 'firstterm' type constraint">
<s:rule context="db:chapter">
<s:assert test="db:title">Chapter should contain title</s:assert>
</s:rule>
</s:pattern>
</s:schema>
return
<result>
<contextNodeXpath>{fn:string-join(local:getXpathDeep($document), "
" )}</contextNodeXpath>
<schematronOutPut>{sch:schematron($document, $schema)}</schematronOutPut>
</result>
That particular Schematron module is rather limited and does not provide a way to return the XPath for the context node from a report or failed assert.
The standard Schematron SVRL output does include the XPath for the items that fire failed asserts or reports.
Norm Walsh has published the ML-Schematron module that wraps the compilation of a Schematron schema into an XSLT using the Schematron stylesheets, and subsequent execution of the compiled XSLT to generate the SVRL report.
You could adjust your module to use it instead (after installing it and the standard Schematron XSLT files in your Modules database):
xquery version "1.0-ml";
declare namespace svrl="http://purl.oclc.org/dsdl/svrl";
import module namespace sch="http://marklogic.com/schematron" at "/schematron.xqy";
let $document :=
document{
<book xmlns="http://docbook.org/ns/docbook">
<title>Some Title</title>
<chapter>
<para>...</para>
</chapter>
</book>
}
let $schema :=
<s:schema xmlns:s="http://purl.oclc.org/dsdl/schematron"
xmlns:db="http://docbook.org/ns/docbook">
<s:ns prefix="db" uri="http://docbook.org/ns/docbook"/>
<s:pattern name="Glossary 'firstterm' type constraint">
<s:rule context="db:chapter">
<s:assert test="db:title">Chapter should contain title</s:assert>
</s:rule>
</s:pattern>
</s:schema>
return
sch:validate-document($document, $schema)
It produces the following SVRL report, which includes the XPath in the location attribute /*[local-name()='book']/*[local-name()='chapter']:
<svrl:schematron-output title="" schemaVersion="" xmlns:schold="http://www.ascc.net/xml/schematron"
xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:db="http://docbook.org/ns/docbook" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
xmlns:svrl="http://purl.oclc.org/dsdl/svrl">
<!---->
<svrl:ns-prefix-in-attribute-values uri="http://docbook.org/ns/docbook" prefix="db"/>
<svrl:active-pattern document=""/>
<svrl:fired-rule context="db:chapter"/>
<svrl:failed-assert test="db:title" location="/*[local-name()='book']/*[local-name()='chapter']">
<svrl:text>Chapter should contain title</svrl:text>
</svrl:failed-assert>
</svrl:schematron-output>

Convert QUrl with percent encoding into string

I use a URL entered by the user as text to initialize a QUrl object. Later I want to convert the QUrl back into a string for displaying it and to check it using regular expression. This works fine as long as the user does not enter any percent encoded URLs.
Why doesn't the following example code work?
qDebug() << QUrl("http://test.com/query?q=%2B%2Be%3Axyz%2Fen").toDisplayString(QUrl::FullyDecoded);
It simply doesn't decode any of the percent-encoded characters. It should print "http://test.com/query?q=++e:xyz/en" but it actually prints "http://test.com/query?q=%2B%2Be%3Axyz%2Fen".
I also tried a lot of other methods like fromUserInput() but I could not make the code work correctly in Qt5.3.
Can someone explain me how to do this and why the above code doesn't work (i.e. showing the decoded URL) even when using QUrl::FullyDecoded?
UPDATE
After getting the fromPercentEncoding() hint, I tried the following code:
QUrl UrlFromUserInput(const QString& input)
{
QByteArray latin = input.toLatin1();
QByteArray utf8 = input.toUtf8();
if (latin != utf8)
{
// URL string containing unicode characters (no percent encoding expected)
return QUrl::fromUserInput(input);
}
else
{
// URL string containing ASCII characters only (assume possible %-encoding)
return QUrl::fromUserInput(QUrl::fromPercentEncoding(input.toLatin1()));
}
}
This allows the user to input unicode URLs and percent-encoded URLs and it is possible to decode both kinds of URLs for displaying/matching. However the percent-encoded URLs did not work in QWebView... the web-server responded differently (it returned a different page). So obviously QUrl::fromPercentEncoding() is not a clean solution since it effectively changes the URL. I could create two QUrl objects in the above function... one constructed directly, one constructed using fromPercentEncoding(), using the first for QWebView and the latter for displaying/matching only... but this seems absurd.
#Conclusion
I've done some research, the conclusion so far is: absurd.
QUrl::fromPercentEncoding() is the way to go and what OP has done in the UPDATE section should've been the accepted answer to the question in title.
I think Qt's document of QUrl::toDisplayString is a little bit misleading :
"Returns a human-displayable string representation of the URL. The output can be customized by passing flags with options. The option
RemovePassword is always enabled, since passwords should never be
shown back to users."
Actually it doesn't claim any decoding ability, the document here is unclear about it's behavior. But at least the password part is true. I've found some clues on Gitorious:
"Add QUrl::toDisplayString(), which is toString() without password. And fix documentation of toString() which said this was the method to
use for displaying to humans, while this has never been true."
#Test Code
In order to discern the decoding ability of different functions. The following code has been tested on Qt 5.2.1 (not tested on Qt 5.3 yet!)
QString target(/*path*/);
QUrl url_path(target);
qDebug() << "[Original String]:" << target;
qDebug() << "--------------------------------------------------------------------";
qDebug() << "(QUrl::toEncoded) :" << url_path.toEncoded(QUrl::FullyEncoded);
qDebug() << "(QUrl::url) :" << url_path.url();
qDebug() << "(QUrl::toString) :" << url_path.toString();
qDebug() << "(QUrl::toDisplayString) :" << url_path.toDisplayString(QUrl::FullyDecoded);
qDebug() << "(QUrl::fromPercentEncoding):" << url_path.fromPercentEncoding(target.toUtf8());
Return QByteArray: QUrl::toEncoded
Return QString: QUrl::url, QUrl::toString, QUrl::toDisplayString, QUrl::fromPercentEncoding
P.S. QUrl::url is just synonym for QUrl::toString.
#Output
[Case 1]: When target path = "%_%" (test the functionality of encoding):
[Original String]: "%_%"
--------------------------------------------------------------------
(QUrl::toEncoded) : "%25_%25"
(QUrl::url) : "%25_%25"
(QUrl::toString) : "%25_%25"
(QUrl::toDisplayString) : "%25_%25"
(QUrl::fromPercentEncoding): "%_%"
[Case 2]: When target path = "Meow !" (test the functionality of encoding):
[Original String]: "Meow !"
--------------------------------------------------------------------
(QUrl::toEncoded) : "Meow%20!"
(QUrl::url) : "Meow !"
(QUrl::toString) : "Meow !"
(QUrl::toDisplayString) : "Meow%20!" // "Meow !" when using QUrl::PrettyDecoded mode
(QUrl::fromPercentEncoding): "Meow !"
[Case 3]: When target path = "Meow|!" (test the functionality of encoding):
[Original String]: "Meow|!"
--------------------------------------------------------------------
(QUrl::toEncoded) : "Meow%7C!"
(QUrl::url) : "Meow%7C!"
(QUrl::toString) : "Meow%7C!"
(QUrl::toDisplayString) : "Meow|!" // "Meow%7C!" when using QUrl::PrettyDecoded mode
(QUrl::fromPercentEncoding): "Meow|!"
[Case 4]: When target path = "http://test.com/query?q=++e:xyz/en" (none % encoded):
[Original String]: "http://test.com/query?q=++e:xyz/en"
--------------------------------------------------------------------
(QUrl::toEncoded) : "http://test.com/query?q=++e:xyz/en"
(QUrl::url) : "http://test.com/query?q=++e:xyz/en"
(QUrl::toString) : "http://test.com/query?q=++e:xyz/en"
(QUrl::toDisplayString) : "http://test.com/query?q=++e:xyz/en"
(QUrl::fromPercentEncoding): "http://test.com/query?q=++e:xyz/en"
[Case 5]: When target path = "http://test.com/query?q=%2B%2Be%3Axyz%2Fen" (% encoded):
[Original String]: "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"
--------------------------------------------------------------------
(QUrl::toEncoded) : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"
(QUrl::url) : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"
(QUrl::toString) : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"
(QUrl::toDisplayString) : "http://test.com/query?q=%2B%2Be%3Axyz%2Fen"
(QUrl::fromPercentEncoding): "http://test.com/query?q=++e:xyz/en"
P.S. I also encounter the bug that Ilya mentioned in comments: Percent Encoding doesn't seem to be working for '+' in QUrl
#Summary
The result of QUrl::toDisplayString is ambiguous. As the document says, the QUrl::FullyDecoded mode must be used with care. No matter what type of URL you got, encode them by QUrl::toEncode and display them with QUrl::fromPercentEncoding when necessary.
As for the malfunction of percent-encoded URLs in QWebView mentioned in OP, more details are needed to debug it. Different function and different mode used could be the reason.
#Helpful Resources
RFC 3986 (which QUrl conforms)
Encode table
Source of qurl.cpp on Gitorious
I am not sure why toDisplayString(QUrl::FullyDecoded) does not work.
After trying several versions I have found that copy.query(QUrl::FullyDecoded) does decode the query part. The Documentation has an example with the the following code does return the decoded URL:
QUrl url("http://test.com/query?q=%2B%2Be%3Axyz%2Fen");
url.setQuery(url.query(QUrl::FullyDecoded), QUrl::DecodedMode);
qDebug() << url.toString();
To solve the problem this way is not optimal because the query part is copied without need.
You can use QUrlQuery::toString(QUrl::FullyEncoded) or QUrl::fromPercentEncoding() for this converting.

Pointer.new(:uint) not converting to proper type for CoreMIDI (RubyMotion)

I'm trying to use CoreMIDI in a RubyMotion project. Here's a simple example of the code:
clientName = "Client"
clientRef = Pointer.new(:uint)
MIDIClientCreate( clientName, nil, nil, clientRef )
See more detailed code and backtrace in the following gist: https://gist.github.com/4299810
That code results in the following error:
(main)> 2012-12-15 14:43:27.410 core-midi-test[42560:c07]
app_delegate.rb:5:in application:didFinishLaunchingWithOptions:':
expected instance of Pointer of type^{OpaqueMIDIClient}', got I'
(TypeError) 2012-12-15 14:43:27.412 core-midi-test[42560:c07] ***
Terminating app due to uncaught exception 'TypeError', reason:
'app_delegate.rb:5:inapplication:didFinishLaunchingWithOptions:':
expected instance of Pointer of type ^{OpaqueMIDIClient}', gotI'
(TypeError)'
The error is apparently with the fourth argument to MIDIClientCreate. The docs for MIDIClientCreate show:
OSStatus MIDIClientCreate (
CFStringRef name,
MIDINotifyProc notifyProc,
void *notifyRefCon,
MIDIClientRef *outClient
);
MIDIClientRef derives from MIDIObjectRef which is defined as a UInt32, so I'm fairly certain that Pointer.new(:uint) is the correct type to use with RubyMotion.
Here is the pertinent portion of the CoreMIDI.bridgesupport file that RubyMotion is using:
<function name='MIDIClientCreate'>
<arg name='name' type='^{__CFString=}' declared_type='CFStringRef'/>
<arg name='notifyProc' function_pointer='true' type='^?' declared_type='MIDINotifyProc'>
<arg type='^{MIDINotification=iI}' declared_type='MIDINotification*' const='true'/>
<arg type='^v' declared_type='void*'/>
<retval type='v' declared_type='void'/>
</arg>
<arg name='notifyRefCon' type='^v' declared_type='void*'/>
<arg name='outClient' type='^^{OpaqueMIDIClient}' declared_type='MIDIClientRef*'/>
<retval type='l' declared_type='OSStatus'/>
</function>
As far as I can tell, the bridgesupport definition should include the necessary plumbing to make the proper conversion. But it's of course, not working.
Is there something wrong with my code or is there something wrong the CoreMIDI.bridgesupport file included with RubyMotion?
I found out by reading the documentation for MacRuby that one can explicitly pass the desired pointer type to the Pointer constructor like so:
clientName = "Client"
clientRef = Pointer.new(MIDIClientRef.type)
MIDIClientCreate( clientName, nil, nil, clientRef )
portName = "Output"
outport = Pointer.new(MIDIPortRef.type)
MIDIOutputPortCreate( clientRef[0], portName, outport )

iframe Onload Visibility

I am trying to hide an iframe until it is loaded by I keep getting an error with the following code:
jquery("some stuff">.html("<iframe frameborder='0' vspace='0' hspace='0' marginwidth='0'
allowtransparency='true' scrolling='no' marginheight='0'
style='visibility:hidden;' onload="this.style.visibility='visible';" width='600'
class='frm'></iframe>").appendTo('body');
But it returns an error "syntax error this.style.visibility".
Can anyone help ?
edit:fixed spelling but now get the error
'missing ) after argument list'
You have a typo. Should be
this.style.visibility='visible';
required exit quotes \ and \
onload=\"this.style.visibility='visible';\"

Resources