goquery insert newline after text found - goquery

I am using "github.com/PuerkitoBio/goquery" to parse numbers from inside 'value' tag in the html document like below
<tab>
<value>1,2,3</value>
<value>2,4,6</value>
<value>5,6,7</value>
</tab>
and what I got with code snippet below is 1,2,32,4,65,6,7 so without newline which is not what I want . I need multiple 3 'values'(to append each of them later to slice) not one
func parseGoQuery(b io.Reader) {
doc, err := goquery.NewDocumentFromReader(b)
fmt.Println(doc.Find("tab").Find("value").Text())
}

try this:
doc.Find("tab").Find("value").Each(func(_ int, value *goquery.Selection) {
fmt.Println(value.Text())
})
The above code iterates over all value elements, and then print the text of each element in one line, which is exactly what you want.

Related

Xquery delete leaves empty lines in xml document - how to remove them? (eXist-db)

In XQuery 3.1 (eXist 4.7) I have an operation that deletes nodes from a stored XML document at /db/apps/myapp/data/list_bibliography.xml that looks like this:
<listBibl xmlns="http://www.tei-c.org/ns/1.0" xml:id="bibliography">
<tei:biblStruct xmlns:tei="http://www.tei-c.org/ns/1.0" type="book" xml:id="Z-BF2WLW8Y">
<tei:monogr>
<tei:title level="m">footitle1</tei:title>
<tei:author>
<tei:name>author name</tei:name>
</tei:author>
<tei:imprint>
<tei:publisher>some city</tei:publisher>
<tei:date>2019</tei:date>
</tei:imprint>
</tei:monogr>
</tei:biblStruct>
<tei:biblStruct xmlns:tei="http://www.tei-c.org/ns/1.0" type="book" xml:id="Z-4KF7YNP3">
<tei:monogr>
<tei:title level="m">footitle2</tei:title>
<tei:author>
<tei:name>author name</tei:name>
</tei:author>
<tei:imprint>
<tei:publisher>some other city</tei:publisher>
<tei:date>2018</tei:date>
</tei:imprint>
</tei:monogr>
</tei:biblStruct>
</listBibl>
The following function:
declare local:delete-bibl()
{
let $bibdoc := doc("/db/apps/myapp/data/list_bibliography.xml")
for $bib in $bibdoc//tei:biblStruct[#xml:id = "Z-BF2WLW8Y"]
return update delete $bib
};
leaves the file with whitespace like this:
<listBibl xmlns="http://www.tei-c.org/ns/1.0" xml:id="bibliography">
<tei:biblStruct xmlns:tei="http://www.tei-c.org/ns/1.0" type="book" xml:id="Z-4KF7YNP3">
<tei:monogr>
<tei:title level="m">footitle2</tei:title>
<tei:author>
<tei:name>author name</tei:name>
</tei:author>
<tei:imprint>
<tei:publisher>some other city</tei:publisher>
<tei:date>2018</tei:date>
</tei:imprint>
</tei:monogr>
</tei:biblStruct>
</listBibl>
Is there some sort of configuration or function that can collapse the white space left by delete?
I tried using instead return update replace $bib with "" but that throws errors as the replacement must be a node.
Many thanks.
There is no configuration option for collapsing the whitespace left by eXist's XQuery Update delete operations.
To work around the error you received when replacing $bib with an empty string, instead replace it with a text node:
update replace $bib with text { "" }

Get last page http request golang

I am doing an http requestlike this one:
resp, err := http.Get("http://example.com/")
Then I am getting the header link:
link := resp.Header.Get("link")
Which gives me a result like this:
<page=3>; rel="next",<page=1>; rel="prev";<page=5>; rel="last"
Question
How can I parse this into a more legible way? I specifically trying to get the last page but firstand nextpage should useful as well.
I tried with Splitsand Regular expressionswithout success.
Are you sure that is the format of the output? It looks like one of ; should be a ,.
A single Link http header with multiple values, should be of the format (notice the comma after "prev")
<page=3>; rel="next",<page=1>; rel="prev",<page=5>; rel="last"
The order should be split on , for each link. Split each link on ; for values or key-value pairs, and then if they value matches <(.*=.*)>, discard the angle brackets and use the remaining key and value.
Here's a solution of how to match your page numbers.
http://play.golang.org/p/kzurb38Fwx
text := `<page=3>; rel="next",<page=1>; rel="prev";<page=2>; rel="last"`
re := regexp.MustCompile(`<page=([0-9]+)>; rel="next",<page=([0-9]+)>; rel="prev";<page=([0-9]+)>; rel="last"`)
matches:= re.FindStringSubmatch(text)
if matches != nil {
next := matches[1]
prev := matches[2]
last := matches[3]
fmt.Printf("next = %s, prev = %s, last = %s\n", next, prev, last)
}
Later Edit: you can probably also use the xml package to achieve the same result, by parsing that output as an XML, but you would need to transform your output a bit.

XQuery "flattening" an element

I am extracting data from an XML file and I need to extract a delimited list of sub-elements. I have the following:
for $record in //record
let $person := $record/person/names
return concat($record/#uid/string()
,",", $record/#category/string()
,",", $person/first_name
,",", $person/last_name
,",", $record/details/citizenships
,"
")
The element "citizenships" contains sub-elements called "citizenship" and as the query stands it sticks them all together in one string, e.g. "UKFrance". I need to keep them in one string but separate them, e.g. "UK|France".
Thanks in advance for any help!
fn:string-join($arg1 as xs:string*, $arg2 as xs:string) is what you're looking for here.
In your currently desired usage, that would look something like the following:
fn:string-join($record/details/citizenships/citizenship, "|")
Testing outside your document, with:
fn:string-join(("UK", "France"), "|")
...returns:
UK|France
Notably, ("UK", "France") is a sequence of strings, just as a query returning multiple citizenships would likewise be a sequence (the entries in which will be evaluated for their string value when passed to fn:string-join(), which is typed as taking a sequence of strings for its first argument).
Consider the following (simplified) query:
declare context item := document { <root>
<record uid="1">
<person>
<citizenships>
<citizenship>France</citizenship>
<citizenship>UK</citizenship>
</citizenships>
</person>
</record>
</root> };
for $record in //record
return concat(fn:string-join($record//citizenship, "|"), "
")
...and its output:
France|UK

How do I prevent xdmp:node-delete() from adding whitespace in my xml doc

I am trying to MOVE a node from one xml document to another. Both documents are using the same namespace. I am trying to accomplish this by doing xdmp:node-insert-child() on the first document then xdmp:node-delete() on the second document in a sequence. The problem is that the xdmp:node-delete() is leaving spaces and returns in my xml doc. How can I keep this from happening?
Here is a code example...
let $documentId := 12345
let $newStatus := 123
let $processNode := $PROCESS-DOC//pex:process[(#documentId = $documentId)]
let $newNode :=
element { QName($TNS, 'process') } {
attribute status { $newStatus },
attribute documentId { $processNode/#documentId },
}
return
if ($processNode and $newNode) then
(xdmp:node-insert-child($PROCESS-COMPLETE-DOC/pex:processes, $newNode),xdmp:node-delete($processNode))
else ()
It sounds like the whitespace is held in text nodes on either side of the node you are deleting. You could verify this by inspecting xdmp:describe($processNode/preceding-sibling::text()) and xdmp:describe($processNode/following-sibling::text()). And if you like, you could xdmp:node-delete some or all of those text nodes too.

Using Vim, how can I make CSS rules into one liners?

I would like to come up with a Vim substitution command to turn multi-line CSS rules, like this one:
#main {
padding: 0;
margin: 10px auto;
}
into compacted single-line rules, like so:
#main {padding:0;margin:10px auto;}
I have a ton of CSS rules that are taking up too many lines, and I cannot figure out the :%s/ commands to use.
Here's a one-liner:
:%s/{\_.\{-}}/\=substitute(submatch(0), '\n', '', 'g')/
\_. matches any character, including a newline, and \{-} is the non-greedy version of *, so {\_.\{-}} matches everything between a matching pair of curly braces, inclusive.
The \= allows you to substitute the result of a vim expression, which we here use to strip out all the newlines '\n' from the matched text (in submatch(0)) using the substitute() function.
The inverse (converting the one-line version to multi-line) can also be done as a one liner:
:%s/{\_.\{-}}/\=substitute(submatch(0), '[{;]', '\0\r', 'g')/
If you are at the beginning or end of the rule, V%J will join it into a single line:
Go to the opening (or closing) brace
Hit V to enter visual mode
Hit % to match the other brace, selecting the whole rule
Hit J to join the lines
Try something like this:
:%s/{\n/{/g
:%s/;\n/;/g
:%s/{\s+/{/g
:%s/;\s+/;/g
This removes the newlines after opening braces and semicolons ('{' and ';') and then removes the extra whitespace between the concatenated lines.
If you want to change the file, go for rampion's solution.
If you don't want (or can't) change the file, you can play with a custom folding as it permits to choose what and how to display the folded text. For instance:
" {rtp}/fold/css-fold.vim
" [-- local settings --] {{{1
setlocal foldexpr=CssFold(v:lnum)
setlocal foldtext=CssFoldText()
let b:width1 = 20
let b:width2 = 15
nnoremap <buffer> + :let b:width2+=1<cr><c-l>
nnoremap <buffer> - :let b:width2-=1<cr><c-l>
" [-- global definitions --] {{{1
if exists('*CssFold')
setlocal foldmethod=expr
" finish
endif
function! CssFold(lnum)
let cline = getline(a:lnum)
if cline =~ '{\s*$'
return 'a1'
elseif cline =~ '}\s*$'
return 's1'
else
return '='
endif
endfunction
function! s:Complete(txt, width)
let length = strlen(a:txt)
if length > a:width
return a:txt
endif
return a:txt . repeat(' ', a:width - length)
endfunction
function! CssFoldText()
let lnum = v:foldstart
let txt = s:Complete(getline(lnum), b:width1)
let lnum += 1
while lnum < v:foldend
let add = s:Complete(substitute(getline(lnum), '^\s*\(\S\+\)\s*:\s*\(.\{-}\)\s*;\s*$', '\1: \2;', ''), b:width2)
if add !~ '^\s*$'
let txt .= ' ' . add
endif
let lnum += 1
endwhile
return txt. '}'
endfunction
I leave the sorting of the fields as exercise. Hint: get all the lines between v:foldstart+1 and v:voldend in a List, sort the list, build the string, and that's all.
I won’t answer the question directly, but instead I suggest you to reconsider your needs. I think that your “bad” example is in fact the better one. It is more readable, easier to modify and reason about. Good indentation is very important not only when it comes to programming languages, but also in CSS and HTML.
You mention that CSS rules are “taking up too many lines”. If you are worried about file size, you should consider using CSS and JS minifiers like YUI Compressor instead of making the code less readable.
A convenient way of doing this transformation is to run the following
short command:
:g/{/,/}/j
Go to the first line of the file, and use the command gqG to run the whole file through the formatter. Assuming runs of nonempty lines should be collapsed in the whole file.

Resources