Golang xml unmarshal html table - html

I have a simple HTML table, and want to get all cell values even if it's HTML code inside.
Trying to use xml unmarshal, but didn't get the right struct tags, values or attributes.
import (
"fmt"
"encoding/xml"
)
type XMLTable struct {
XMLName xml.Name `xml:"TABLE"`
Row []struct{
Cell string `xml:"TD"`
}`xml:"TR"`
}
func main() {
raw_html_table := `
<TABLE><TR>
<TD>lalalal</TD>
<TD>papapap</TD>
<TD>fafafa</TD>
<TD>
<form action=\"/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method=POST>
<input type=hidden name=acT value=\"Dev\">
<input type=hidden name=acA value=\"Anyval\">
<input type=submit name=submit value=Stop>
</form>
</TD>
</TR>
</TABLE>`
table := XMLTable{}
fmt.Printf("%q\n", []byte(raw_html_table)[:15])
err := xml.Unmarshal([]byte(raw_html_table), &table)
if err != nil {
fmt.Printf("error: %v", err)
}
}
As an additional info, I don't care about cell content if it's HTML code (take only []byte / string values). So I may delete cell content before unmarshaling, but this way is also not so easy.
Any suggestions with standard golang libs would be welcome.

Sticking to the standard lib
Your input is not valid XML, so even if you model it right, you won't be able to parse it.
First, you're using a raw string literal to define your input HTML as a string, and raw string literals cannot contain escapes. For example this:
<form action=\"/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method=POST>
You can't use \" in a raw string literal (you can, but it will mean exactly those 2 characters), and you don't have to, use a simple quotation mark: ".
Next, in XML you cannot have attributes without putting their values in quotes.
Third, each element must have a matching closing element, your <input> elements are not closed.
So for example this line:
<input type=hidden name=acT value=\"Dev\">
Must be changed to:
<input type="hidden" name="acT" value="Dev" />
Ok, after these the input is a valid XML now.
How to model it? Simple as this:
type XMLTable struct {
Rows []struct {
Cell string `xml:",innerxml"`
} `xml:"TR>TD"`
}
And the full code to parse and print contents of <TD> elements:
raw_html_table := `
<TABLE><TR>
<TD>lalalal</TD>
<TD>papapap</TD>
<TD>fafafa</TD>
<TD>
<form action="/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method="POST">
<input type="hidden" name="acT" value="Dev" />
<input type="hidden" name="acA" value="Anyval" />
<input type="submit" name="submit" value="Stop" />
</form>
</TD>
</TR>
</TABLE>`
table := XMLTable{}
err := xml.Unmarshal([]byte(raw_html_table), &table)
if err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Println("count:", len(table.Rows))
for _, row := range table.Rows {
fmt.Println("TD content:", row.Cell)
}
Output (try it on the Go Playground):
count: 4
TD content: lalalal
TD content: papapap
TD content: fafafa
TD content:
<form action="/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method="POST">
<input type="hidden" name="acT" value="Dev" />
<input type="hidden" name="acA" value="Anyval" />
<input type="submit" name="submit" value="Stop" />
</form>
Using a proper HTML parser
If you can't or don't want to change the input HTML, or you want to handle all HTML input not just valid XMLs, you should use a proper HTML parser instead of treating the input as XML.
Check out https://godoc.org/golang.org/x/net/html for an HTML5-compliant tokenizer and parser.

Once your input is valid HTML (your snippet is missing quotes in attributes), you can configure a xml.Decoder with entities and autoclose maps (and make it non-strict), which will end up working :
Run my modified version here.
package main
import (
"encoding/xml"
"fmt"
"strings"
)
type XMLTable struct {
Rows []struct {
Cell string `xml:",innerxml"`
} `xml:"TR>TD"`
}
func main() {
raw_html_table := `
<TABLE><TR>
<TD>lalalal</TD>
<TD>papapap</TD>
<TD>fafafa</TD>
<TD>
<form action="/addedUrl/;jsessionid=KJHSDFKJLSDF293847odhf" method="POST">
<input type="hidden" name="acT" value="Dev">
<input type="hidden" name="acA" value="Anyval">
<input type="submit" name="submit" value="Stop">
</form>
</TD>
</TR>
</TABLE>`
table := XMLTable{}
decoder := xml.NewDecoder(strings.NewReader(raw_html_table))
decoder.Entity = xml.HTMLEntity
decoder.AutoClose = xml.HTMLAutoClose
decoder.Strict = false
err := decoder.Decode(&table)
if err != nil {
fmt.Printf("error: %v", err)
}
fmt.Printf("%#v\n", table)
}

Related

how to capture values ​of type int - GO, GIN, POSTFORM

I'm building a simple crud integrated with html. My crud consists of a table of products, in my table I have the following fields:
package models
type Produtos struct {
IDProd int `json:"id_Prod" gorm:"primaryKey"`
NomeProduto string `json:"nome_produto"`
Quantidade int `json:"quantidade"`
PrecoProduto int `json:"preco_produto"`
}
I'm trying to make a fullstack crud, but I'm stuck in the part where I enter the Quantity and Product_Price values.
My GO code is like this:
package handlers
import (
"github.com/gin-gonic/gin"
"github.com/guilherm5/crud/models"
)
func (h Handler) CreateProduct(c *gin.Context) {
//CREATE IN WEBSITE
var createHTML = []models.Produtos{{
NomeProduto: c.Request.FormValue("nome_produto"),
Quantidade: c.Request.FormValue("quantidade"),
PrecoProduto: c.Request.FormValue("preco_produto")}}
h.DB.Create(&createHTML)
my html code like this:
<section class="container-principal">
<form action="/create" method="post" enctype="multipart/form-data">
<div class="title">
<h1>Crie seu usuario</h1>
</div>
<div class="single-input">
<input placeholder="nome do produto" type="text" id="nome_produto" name="nome_produto">
</div>
<div class="single-input">
<input placeholder="quantidade em estoque" type="number" id="quantidade" name="quantidade">
</div>
<div class="single-input">
<input placeholder="preco do produto" type="number" id="preco_produto" name="preco_produto">
</div>
<a class="new" href="/"><button id="botao" type="submit" class="glow-on-hover" type="button">Enviar</button></a>
</form>
my problem is in the GO code, in my Quantity part it is issuing the following error:
my problem is in the GO code, in my Quantity part: c.Request.FormValue("quantidade"), it is issuing the following error:
cannot use c.Request.FormValue("quantidade") (value of type string) as int value in struct literal
the parameter c.Request.FormValue does not accept int in its entries, how can I solve this? Is there any other parameter to be used? can someone help me?
It looks like the problem is that you are trying to assign a string value to an int field in your Produtos struct. The FormValue function returns a string, so you'll need to convert it to an integer before you can assign it to the Quantidade field.
Here is an example of what you can do:
import "strconv"
...
quantityString := c.Request.FormValue("quantidade")
quantity, err := strconv.Atoi(quantityString)
if err != nil {
// handle the error, for example by returning a response to the user
}
var createHTML = []models.Produtos{{
NomeProduto: c.Request.FormValue("nome_produto"),
Quantidade: quantity,
PrecoProduto: c.Request.FormValue("preco_produto")}}

Differentiate multiple input form inside forEach statement

I have an array of String, the length is variable. I need to create for each String two buttons: buy and remove. They manage the quantity of the correspondent element. Like this:
Resoult.
I tried this, works but it's not clear.
String go = request.getParameter("go");
if ((go != null)){
String[] info = go.split(",");
int index = Integer.parseInt(info[1]);
if (info[0].equals("+")) {
++quantita[index];
} else {
--quantita[index];
}}
...
<c:forEach var="i" begin="0" end="${length-1}" >
<%
int i = (int) pageContext.getAttribute("i");
out.print(products[i] + " (" + quantita[i] +" in cart)");
%>
<input type=submit name="go" value="-,${i}"/>
<input type=submit name="go" value="+,${i}"/><br>
</c:forEach>
Use <button type="submit"> instead of <input type="submit">. This HTML element allows you to set content via children rather than via value attribute. This way you can simply use the name attribute to indicate the action and the value attribute to indicate the identifier.
<button type=submit name="decrease" value="${i}">-</button>
<button type=submit name="increase" value="${i}">+</button>
String decrease = request.getParameter("decrease");
String increase = request.getParameter("increase");
if (decrease != null) {
--quantity[Integer.parseInt(decrease)];
}
else if (increase != null) {
++quantity[Integer.parseInt(increase)];
}
Is that clearer?

How to use XQuery and HTML to upload files to MarkLogic?

As my question states I am trying to use XQuery and a simple HTML form to upload files to my MarkLogic local database. I already connected to a HTTP-server.
My code now looks like this:
Form:
<div id="content">
<form name="test" action="upload.xqy?uid={xdmp:random()}" method="post"
enctype="multipart/form-data">
<p><label>File to upload:
<input type="file" class="name" name="upload" size="50"/></label></p>
<p><input type="submit" value="Upload and Get Results"/></p>
</form>
</div>
upload.xqy:
let $filename := xdmp:get-request-field-filename("upload")
let $collection := "semansysdocs"
let $fileLocation := xdmp:get-request-path()
return
xdmp:document-load($fileLocation,
map:map() => map:with("uri", $filename)
=> map:with("permissions", xdmp:default-permissions())
=> map:with("collections", $collection)
)
The docs simply state to use xdmp:document-insert(), but I do not understand where.
Is there a way to specify where the file is coming from to get the $fileLocation, or do i need an other method to do this?
Thank you!
Your form is already sending both filename and file data. xdmp:get-request-field-filename('upload') returns the original file path as sent by the browser, and xdmp:get-request-field('upload') will get you the data. I think you are looking for something like:
let $filename := xdmp:get-request-field-filename("upload")
let $file := xdmp:get-request-field("upload")
let $collection := "semansysdocs"
return
xdmp:document-insert(
$filename,
$file,
xdmp:default-permissions(),
(xdmp:default-collections(), $collection)
)
HTH!

Html form (insert xquery) save in xml

I have an html form, when I press the submit button I want to take the information and use the functions of Xquery so that with an (insert) xquery will be saved in the xml.
--html--
<html>
<body>
<form action="insert.xq">
<span ="label">Name:</span>
<input type="text"/>
<span ="label">Telephone:</span>
<input type="text"/>
<span ="label">Website:</span>
<input type="text"/>
<span ="label">Date:</span>
<input type="text"/>
<!-- Buttons submit and reset-->
<input type="submit" value="Submit"/>
<input type="reset" value="Delete"/>
</form>
</body>
</html>
--exist-db XQUERY--
xquery version "3.1";
declare namespace exist="http://exist.sourceforge.net/NS/exist";
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
declare namespace request = "http://exist-db.org/xquery/request";
update insert
<supplier id=" ">
<name> </name>
<telephone> </telephone>
<website> </website>
<date> </date>
</supplier>
into doc("suppliers.xml")//supplier
--xml--
<?xml version="1.0" encoding="UTF-8"?>
<suppliers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="validate.xsd">
<supplier id="1">
<name>Microsoft</name>
<telephone>943715587</telephone>
<website>www.microsoft.com</website>
<date>10/08/2016</date>
</supplier>
</suppliers>
Sorry for my english.
Parameters in the HTTP REST interface are accessed into variables in an XQuery using the request function set as in:
let $name := request:get-parameter("name","")
let $telephone := request:get-parameter("telephone","")
let $website := request:get-parameter("website","")
let $date := request:get-parameter("date","")
Then used as you would in the rest of the code as a XQuery variable:
update insert
<supplier id=" ">
<name>{$name}</name>
...
Now, that is a start. Your HTML needs name attributes on the input elements to pass them as parameters into the query. You need a return after the let's to return and the http request should be set to GET. And not knowing your system, the query and the documents would have to be open to all unless you are in some session-based environment and the HTML GET can find the XQuery based on some pathing in your controller or something.
This is essentially the same as http://path/to/myquery.xm?name=John%20Doe&telephone=123456789 ... and you want to grab the name and telephone.

How to parse form array in golang Beego

How to parse html form array with Beego.
<input name="names[]" type="text" />
<input name="names[]" type="text" />
<input name="names[]" type="text" />
Go Beego
type Rsvp struct {
Id int `form:"-"`
Names []string `form:"names[]"`
}
rsvp := Rsvp{}
if err := this.ParseForm(&rsvp); err != nil {
//handle error
}
input := this.Input()
fmt.Printf("%+v\n", input) // map[names[]:[name1 name2 name3]]
fmt.Printf("%+v\n", rsvp) // {Names:[]}
Why Beego ParseForm method return an empty names?
How to get values into rsvp.Names?
Thanks #ysqi for giving me a hint. I am adding a little detailed example to parse associate array like form data in beego
Here is my form structure:
<input name="contacts[0][email]" type="text" value="a1#gmail.com"/>
<input name="contacts[0][first_name]" type="text" value="f1"/>
<input name="contacts[0][last_name]" type="text" value="l1"/>
<input name="contacts[1][email]" type="text" value="a2#gmail.com"/>
<input name="contacts[1][first_name]" type="text" value="f2"/>
<input name="contacts[1][last_name]" type="text" value="l2"/>
golang(beego) code:
contacts := make([]map[string]string, 0, 3)
this.Ctx.Input.Bind(&contacts, "contacts")
contacts variable:
[
{
"email": "user2#gmail.com",
"first_name": "Sam",
"last_name": "Gamge"
},
{
"email": "user3#gmail.com",
"first_name": "john",
"last_name": "doe"
}
]
Now you can use it like:
for _, contact := range contacts {
contact["email"]
contact["first_name"]
contact["last_name"]
}
As you can see from the implementation of the FormValue method of the Request, it returns the first value in case of multiple ones:
http://golang.org/src/pkg/net/http/request.go?s=23078:23124#L795
It would be better to get the attribute itself r.Form[key] and iterate over all the results manually. I am not sure how Beego works, but just using the raw
Request.ParseForm and Request.Form or Request.PostForm maps should do the job.
http://golang.org/src/pkg/net/http/request.go?s=1939:6442#L61
You can do like this : see doc
v := make([]string, 0, 3)
this.Ctx.Input.Bind(&v, "names")