Loop in XQuery repeats results several times - xquery

I have a function which returns paragraphs from the text. So I'm comparing the <anchor> tag's attribute number(#n) to the <notes> tag's attribute number, if it's the same I want to print it with the tooltip if not I just want to print out the paragraph.
declare function letter:text_trans($node as node(), $model as map(*))
{
let $resource := collection('/db/apps/Tobi-oshki/data')
for $ab in $resource//tei:div[#type="translation"]/tei:ab
for $note in $resource//tei:div[#type="notes"]/tei:note
return
if (data($note/#n) eq data($ab/tei:anchor/#n))
then
<div class="tooltip">{$ab}
<span class="tooltiptext"> {data($note/#n)}.{$note}</span>
</div>
else
<p> {$ab} </p>
};
In <notes> I have three notes and when it loops over the notes, each paragraph is returned three times.
How can I change it so it returns the paragraphs only one time?
I am using xquery version "3.1";

Inside the for loop on the $ab, let a variable for the $note and select notes that have #n attribute values that match the $ab, then if there is a matching $note, use it, else return the <p> using just the $ab:
let $resource := collection('/db/apps/Tobi-oshki/data')
for $ab in $resource//tei:div[#type="translation"]/tei:ab
let $note := $resource//tei:div[#type="notes"]/tei:note[#n = $ab/tei:anchor/#n]
return
if ($note)
then
<div class="tooltip">{$ab}
<span class="tooltiptext"> {data($note/#n)}.{$note}</span>
</div>
else
<p> {$ab} </p>
With this input:
<tei:doc>
<tei:div type="notes">
<tei:note n="1">note1</tei:note>
<tei:note n="2">note2</tei:note>
</tei:div>
<tei:div type="translation">
<tei:ab><tei:anchor n="1">translated note1</tei:anchor></tei:ab>
<tei:ab><tei:anchor n="3">translated note3</tei:anchor></tei:ab>
</tei:div>
</tei:doc>
the code above produces this output:
<div class="tooltip">
<tei:ab xmlns:tei="tei">
<tei:anchor n="1">translated note1</tei:anchor>
</tei:ab>
<span class="tooltiptext">1.<tei:note n="1" xmlns:tei="tei">note1</tei:note>
</span>
</div>
<p>
<tei:ab xmlns:tei="tei"><tei:anchor n="3">translated note3</tei:anchor></tei:ab>
</p>

Related

DomCrawler filterXpath for emails

In my project I am trying to use filterXPath for emails. So I get an E-Mail via IMAP and put the mail body into my DomCrawler.
$crawler = new Crawler();
$crawler->addHtmlContent($mail->textHtml); //mail html content utf8
Now to my issue. I only want the plain text of the mail body, but still remain all new lines spaces etc - the exact same as the mail looks just in plain text without html (still with \n\r etc).
For that reason I tried using $crawler->filterXPath('//body/descendant-or-self::*/text()') to get every text node inside the mail.
However my test-mail containts html like:
<p>
<u>
<span>
<a href="mailto:mail#example.com">
<span style="color:#0563C1">mail#example.com</span>
</a>
</span>
</u>
<span>
</span>
<span>·</span>
<span>
<b>
<a href="http://www.example.com">
<span style="color:#0563C1">www.example.com</span>
</a>
</b>
<p/>
</span>
</p>
In my mail this looks like mail#example.com · www.example.com (in one single line).
With my filterXPath I get multiple nodes which result in following (multiple lines):
mail#example.com
· wwww.example.com
I know that probably the 
 might be the problem, which is a \r, but since I can't change the html in the mail, I need another solution - as mentioned before in the mail it is only a single line.
Please keep in mind, that my solution has to work for every mail - I do not know how the mail html looks like - it can change every time. So I need a generic solution.
I already tried using strip_tags too - this does not change the result at all.
My current approach:
$crawler = new Crawler();
$crawler->addHtmlContent($mail->textHtml);
$text = "";
foreach ($crawler->filterXPath('//body/descendant-or-self::*/text()') as $element) {
$part = trim($element->textContent);
if($part) {
$text .= "|".$part."|\n"; //to see whitespaces etc
}
}
echo $text;
//OUTPUT
|mail#example.com|
|·|
| |
|www.example.com|
| |
I believe something like this should work:
$xpath = new DOMXpath($crawler);
$result = $xpath->query('(//span[not(descendant::*)])');
$text = "";
foreach ($result as $element) {
$part = trim($element->textContent);
if($part) {
$text .= "|".$part."|"; //to see whitespaces etc
}
}
echo $text;
Output:
|mail#example.com||·||www.example.com|
Do note that you are dealing with two different ways to treat whitespace only text nodes: HTML has its own rules about if those are rendered (the difference are mainly between block elements and inline elements and also includes normalization) and XPATH works over a document tree provided by a parser (or DOM API) which has its own configuration about preserving or not those whitespace only text nodes. Taking this into account, one solution could be to use the string() function to get the string value of the element containing the email:
For this input:
<root>
<p>
<u>
<span>
<a href="mailto:mail#example.com">
<span style="color:#0563C1">mail#example.com</span>
</a>
</span>
</u>
<span>
</span>
<span>·</span>
<span>
<b>
<a href="http://www.example.com">
<span style="color:#0563C1">www.example.com</span>
</a>
</b>
<p/>
</span>
</p>
</root>
This XPath expresion:
string(/root)
Outputs:
mail#example.com
·
www.example.com
Check in here

ACF into shortcode

Hello good people of StackOverflow, I was wondering is there any way I can use advanced custom fields in shortcode?
function highlight($atts) {
return '
<div class="col-lg-6 ">
<div class="highlighted">
<p class="page-title">TEST</p>
</div>
</div>';
}
add_shortcode('scbox', 'highlight');
so I would like to put something like {{ the_field('text') }} where the "TEST" is now, I'm using blade template if its of any help
You can use the get_field() function to obtain the value that you are looking for. (get_field() will return the value, whereas the_field() will print the value wherever invoked.)
You can then concatenate the value into your returned string:
function highlight($atts) {
$text = get_field('text');
return '
<div class="col-lg-6 ">
<div class="highlighted">
<p class="page-title">' . $text . '</p>
</div>
</div>';
}

Trouble using xmldb:store with collection name with space

I cannot seem to get this right. I have a system where the web user is running a jQuery request to add a new document. The code works perfect if the collection they are storing to have no spaces in the name. This code is:
xquery version "3.0";
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
let $specialty := request:get-parameter("specialty", "")
let $collection := xmldb:encode-uri($specialty)
let $docnum := request:get-parameter("docnum", "")
let $title := request:get-parameter("title", "")
let $file := concat($docnum, '.xml')
let $path := concat($collection, '/', $file)
let $content := <article>
<div
class="content"
doc="{$docnum}"
title="{xmldb:decode($title)}">
<div
class="panel">
<h1>First Panel</h1>
<p>Content goes here</p>
</div>
</div>
</article>
return
let $new_article := xmldb:store($collection, $file, $content, 'application/xml')
return
let $changepermiss := sm:chmod($new_article, 'rw-rw----')
return
<li
class="file"
data-xpath="{$path}"
>
<a
data-xpath="{$path}"
onclick="doc_open('{$path}')"
href="#"><span
class="glyphicon glyphicon-tags"></span>   {$docnum, ': ', xmldb:decode($title)}</a>
</li>
Now, if the collection name that comes from the request contains a space ... like this (after encoding) ... it fails.
"/db/Test/data/Core/Test%20Collection"
The error is:
exerr:ERROR Could not locate collection: /db/Test/data/Core/Test%20Collection
This occurs at this line: xmldb:store($collection, $file, $content, 'application/xml') with $collection not be recognized because of the space.
Now, to test things out, I run this and it is fine.
xquery version "3.0";
declare option exist:serialize "method=xhtml media-type=text/html indent=yes";
let $test := "/db/EIDO/data/Core/Disease%20Prevention"
let $content := <article>
<div
class="content"
doc="D777"
title="Test Document">
<div
class="panel">
<h1>First Panel</h1>
<p>Content goes here</p>
</div>
</div>
</article>
return
let $newdoc := xmldb:store($test, "test.xml", $content, 'application/xml')
return
$newdoc
I cannot understand where I am going wrong in trying to reference the collection with a space in xmldb:store.
NOTE: As I said, the code works if there is no space in the name of the collection.
I have tried many combinations of encoding the URL and making a string from it but nothing seems to work.
If your collection or resource names are possibly going to contain characters that need to be encoded, you need to use xmldb:encode-uri() on the names. In your first sample, you encode the collection name ($collection) but not the resource name ($file). In your second sample, you pre-encode the collection name, but the resource name contains no characters that need to be encoded; so you've fully accounted for the encoding.
Take care to ensure that the collection name, as encoded, does exist. If not, you should pre-create the collection. This could actually be the cause of the error you cite.
When you create links to these resources in HTML output, take care not to double-encode them.
You might find it useful to reference an app that handles encoding well. See the source to eXide https://github.com/wolfgangmm/eXide.
The answer was permission issue (although I am a bit lost at that).
The collection had rw-rw-r-- and the user is in the group and is in fact the owner of the collection.
When I change to include execute (rwxrwxr--) it works as expected. Confusing, but apparently execute permission in required on the collection that is going to be stored into.

Meteor Markdown shows only the first line

I want to highlight my code. So I use simple:highlight.jsand markdownpackages. However only the first line will be highlighted and the rest of the code is shown as blank text outside <pre> tags.
TEMPLATE
<div class="card">
<p class="front">
{{#if cards.frontIsCode}}
{{#markdown}}
{{cards.front}}
{{/markdown}}
{{else}}
{{cards.front}}
{{/if}}
</p>
</div>
RENDERED HTML
<p class="front">
<pre><code class="hljs javascript"><span class="hljs-keyword">var</span> x = <span class="hljs-number">10</span>;
</code></pre>
<p>var y = z;
var func = function(block) {
return block * x;
}</p>
</p>
The object looks like this "front: "var x = 10;↵var y = z;↵var func = function(block) {↵return block * x;↵}""
The whole repo is here: https://github.com/mvaisanen/flashcards
it's simply because your indent!!
things like
{{#markdown}}
{{cards.front}}
{{/markdown}}
won't work, however
{{#markdown}}
{{cards.front}}
{{/markdown}}
works properly.
Do NOT apply any intends even in the html template.
Hope it helps

xquery- how to assign a number(in sequence) when obtaining a number of records via single query using FLWOR expression

While trying to process and obtain data from an XML document, I want to obtain a number of records using a single FLWOR expression-- I am doing this by using the 'let' clause to obtain the data-- so I have a number of rows of data.
Eg.
<div id="main">
<p> Text #1</p>
<p> Text #2</p>
<p> Text #3</p>
<p> Text #4</p>
</div>
Now, I understand how to get the 4 'p' elements -- however I would like to also assign a sequence number to each line -- viz. I want to obtain the text this way--
<data>Text #1</data><sequence> Sequence #1</sequence>
<data>Text #2</data><sequence> Sequence #2</sequence>
<data>Text #3</data><sequence> Sequence #3</sequence>
<data>Text #4</data><sequence> Sequence #4</sequence>
There sure is a more elegant way than doing it like this.... but it works:
let $t := <div id="main">
<p>Text A</p>
<p>Text B</p>
<p>Text C</p>
<p>Text D</p>
</div>
for $pos in $t/p/position()
let $p := $t/p[$pos]
return (
<data>{ $p/text() }</data>,
<sequence>Sequence { $pos }</sequence>
)
While I'm not completely sure what string value you would to have for the <sequence/> element, one solution could look as follows:
for $p in <div id="main">
<p>Text #1</p>
<p>Text #2</p>
<p>Text #3</p>
<p>Text #4</p>
</div>/p
return (
<data>{ $p/text() }</data>,
<sequence>Sequence { replace($p, 'Text ', '') }</sequence>
)
You can use the at keyword in the FLWOR expression's for clause:
declare variable $div :=
<div id="main">
<p> Text #1</p>
<p> Text #2</p>
<p> Text #3</p>
<p> Text #4</p>
</div>;
for $p at $pos in $div/p
return (
<data>{$p/text()}</data>,
<sequence>Sequence #{$pos}</sequence>
)

Resources