Bash Script to generate HTML Template - bash

I want a Bash script that generates a HTML template. The template will include libraries based on the input arguments at the command line. Here is my idea:
#!/bin/bash
function libraries
{
if [ "$1" == "bootstrap" ]; then
echo "<link type="text/css" rel="stylesheet" href="css/bootstrap.css" />"
fi
}
##### Main
cat << _EOF_
<!DOCTYPE html>
<html>
<head>
<title> </title>
$(libraries)
</head>
<body>
</body>
</html>
_EOF_
When I run ./template_creator.sh bootstrap I get this output:
<!DOCTYPE html>
<html>
<head>
<title> </title>
</head>
<body>
</body>
</html>
If I don't include the if statement and just echo, it outputs fine. So I am thinking the trouble is in the if statement. Any suggestions?

You can use printf to inject variables in your template.
In your template use the printf formats (eg. %s) as inserting points.
This way you can even use a file for your template (calling it with tpl=$(cat "main.tpl") and handle your variables in your script.
libraries() {
if [ "$1" == "bootstrap" ]; then
link='<link type="text/css" rel="stylesheet" href="css/bootstrap.css" />'
printf "$tpl" "$link"
fi
}
##### Main
read -d '' tpl << _EOF_
<!DOCTYPE html>
<html>
<head>
<title> </title>
%s
</head>
<body>
</body>
</html>
_EOF_
libraries "$1"

Inside a function, $1 refers to the first argument passed to that function, not the first argument passed to the script. You can either pass the script's first argument on to the function by using $(libraries "$1") in the here-document, or assign it to a global variable at the beginning of the script and then use that in the function.

Instead of $(libraries) write $(libraries) $1.

Related

Thymeleaf 3 (not) building layout sequentially?

I know about existance of layout dialect for Thymeleaf (https://github.com/ultraq/thymeleaf-layout-dialect), but before jumping into said dialect dating pre thymeleaf 3, I wanted to explore newer fragment expressions (introduced in TL3).
So as per docs - I can define base.html that will work almost the same way that the layout dialect allows fragments to be managed.
base.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="base(title, links, content)">
<title th:replace="${title}"></title>
<link rel="stylesheet" type="text/css" media="all" href="/css/main.css" />
<th:block th:replace="${links}"></th:block>
</head>
<body>
<header th:replace="~{header :: header}"></header>
<div th:replace="${content}"></div>
<footer th:replace="~{footer::footer}"></footer>
</body>
</html>
...but then when I use this in my home.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="base::base(~{::title}, ~{::link}, ~{::content})">
<title th:text="#{home.title}"></title>
<link rel="stylesheet" th:href="test">
<link rel="stylesheet" th:href="test1">
<link rel="stylesheet" th:href="test2">
</head>
<body>
<div th:fragment="content">
<span>TEST CONTENT</span>
</div>
</body>
</html>
...it acts like home.html only evaluates itself and arguments it passes to base.html because this is product:
<!DOCTYPE html>
<html>
<head>
<title>My home page</title>
<link rel="stylesheet" type="text/css" media="all" href="/css/main.css" />
<link rel="stylesheet" href="test"><link rel="stylesheet" href="test1"><link rel="stylesheet" href="test2">
</head>
<body>
<div>
<span>TEST CONTENT</span>
</div>
</body>
</html>
As you can see, title is evaluated in home.html and passed to base.html, same goes for 3 links I provided in home.html. Also content gets passed and placed in proper place. What is missing? Everything that is not argument of base.html fragment. Thymeleaf ignores evaluating my header and footer and just removes them.
Let me just note that If I were to place header/footer in home.html inside content they will be evaluated like they should - from header.html with selector header: "~{header :: header}".
Am I missing something crucial as to how this whole thing is supposed to work? What's the point of being able to define fragments that will work as layout if they can't evaluate themselves and need everything passed from "child file (caller)"?
It seems to me you mixed fragments and replacements together. The head replacement works well because you declared it correctly. But why did you declare a th:replace attribute in base.html like
<header th:replace="~{header :: header}"></header>? It is not within a fragment, not a parameter, therefore it must be replaced from somewhere.
As far as I understand you expect fragments in base.html and replacements in home.html. Then make both the header and footer fragments and declare corresponding th:replace tags in home.html.
<div th:replace="${content}"></div>
This also doesn't work because it is not within a th:fragment tag.
The bottom line: fix the hierarchy of tags and the logic of replacement.
Like Xaltotun pointed out - I needed to fix my stuff.
I've placed base(args...) in header so my passed fragments werent visible in body, thus everything failed.
Let me just add some code:
Layout.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:fragment="layout(content, title, meta)">
<head>
<title th:text="${title}">Default Title</title>
<link rel="stylesheet" type="text/css" media="all" href="/css/style.css" />
<th:block th:replace="${meta}" />
</head>
<body>
<div class="viewport">
<header class="website-header">
...
</header>
<div th:replace="${content}"></div>
<th:block th:replace="staticContentTemplate :: testFragment" />
<footer class="website-footer">
...
</footer>
</div>
</body>
</html>
Home.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="layout::layout(~{::content}, #{home.title}, ~{::meta})">
<head>
<th:block th:fragment="meta">
<link rel="stylesheet" th:href="test">
</th:block>
</head>
<body>
<div th:fragment="content">
<span>TEST CONTENT</span>
</div>
</body>
</html>
Result is as expected:
Home.html provides title, content and meta.
Layout.html gives everything else, and also copies additional template from different source staticContentTemplate :: testFragment
Tip for others: notice that I placed args in layout in this order - content since its always present, title that can be optional and meta that might not be needed - this allows us to call layout with just content: layout(~{::content}) (shorter = better).

How to add comment into an XML file

How do I add a comment into an XML file using Nokogiri?
For example, I have an existing html file. I want to add <!--doc-->. How should I do it so I get:
...
<body>
<!--doc-->
</body>
...
I'd use:
require 'nokogiri'
doc = Nokogiri::HTML('<html><body></body></html>')
doc.at('body') << '<!-- foo -->'
puts doc.to_html
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html><body><!-- foo --></body></html>
Or you can use a bit longer code:
doc.at('body').add_child('<!-- foo -->')
Which results in the same thing.
It gets a little more interesting/complicated if <body> has more nodes, and you care where the comment goes, but that's still basically locating where you want the comment to be inserted, and then doing one of the above.
I use following code fix:
require 'nokogiri'
d = Nokogiri::HTML(%Q(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
</body>
</html>
))
d.css('body')[0].add_child(Nokogiri::XML::Comment.new(d, "doc"))
puts d.to_s

Bash-Shell script show source code, not html

It's weird that my shell script in website show the whole source code, not the html that I want.
My script is:
#!/bin/sh
echo "Content-type: text/html"
echo ""
cat << EOF
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<title>test</title>
<link type="text/css" href="../jquery/css/redmond/jquery-ui-custom.min.css" rel="stylesheet">
<script type="text/javascript" src="../jquery/js/jquery.min.js"></script>
<script type="text/javascript" src="../jquery/js/jquery-ui-custom.min.js"></script>
<script type="text/javascript">
//<![CDATA[
if(verifiedUser == "")
window.top.location.href = "/";
//]]>
</script>
</head>
<body>
<table align="center">
<tr><td align="right">Product Name</td><td align="left">
</td></tr>
<tr><td align="right">Hardware Version</td><td align="left">
</td></tr>
<tr><td align="right">Firmware Version</td><td align="left">
</td></tr>
</table>
</body>
</html>
EOF
and what the .cgi file show is just that code!
My cgi file is in the same directory of the html files, because the main directory is in /mnt, so not put in /home/www/cgi-bin/ as usual.
What's the reasonable problem can cause this situation?
Any advice appreciated!
AFAIK, the separator between header section & the html data should be a blank line in CRLF format.
Try this:
echo -e "Content-type: text/html\r"
echo -e "\r"
cat << 'EOF'
---remaining HTML data---
EOF
Note: I have also changed cat << EOF to cat << 'EOF' to prevent any variable expansion. Revert it if variable/command expansion is needed.
#Barmar has the right idea - Your server is very likely not configured to run those files, but rather send the file directly to the client. So it's a configuration issue, not a programming one.

How to keep special characters in template variables on the commandline with pandoc?

I am trying to set a template variable with a string containing an umlaut. The body content is converted correctly, but the variable looses its special characters.
If I have a simple template var-template.md
<!DOCTYPE html>
<html>
<head>
<title>$title$</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<div>
$for(navi)$<button name="navi" value="$navi$">$navi$</button>$endfor$
</div>
<div>
$body$
</div>
</html>
and try to convert with variables set:
echo Hällo Wörld | pandoc -w html --template=var-template -V navi="Übung 1" -V title="Laß das döch"
it outputs:
<!DOCTYPE html>
<html>
<head>
<title>La� das d�ch</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<div>
<button name="navi" value="�bung 1">�bung 1</button>
</div>
<div>
<p>Hällo Wörld</p>
</div>
</html>
So the body text is converted correctly, but the variables are not.
Is this a bug or a mistake?
I am on ubuntu 12.04 with pandoc 1.9.1 ... do I have to manually update from the repository-version to a newer on?
I just tried this with the latest pandoc release, and it worked fine, so you may just need to upgrade. You should also make sure that your locale is UTF-8.

Can I put HTML into a variable?

Using the Sinatra library, I'm trying to condense two functions that display HTML code into a single function. Both these functions differ by only a small amount of HTML.
Here's an example.
def make_start_page()
<<EOS
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<p> Hello </p>
<img src="..." />
</body>
</html>
EOS
end
def make_guess_page()
<<EOS
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<p> Something different </p>
<a href="..." >1</a>
</body>
</html>
EOS
end
In the Ruby function that will call these two functions, I was wondering if it is possible to take the small portion of HTML that differs and pass it to a single, condensed version of these two functions that will display the page.
def handle()
if 1
var = "<p> Hello </p>
<img src="..." />"
elsif 2
var = "<p> Something different </p>
<a href="..." >1</a>"
make_start_guess_page(var)
end
You can interpolate variables in heredoc:
def make_start_page(var)
<<EOS
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
#{var}
</body>
</html>
EOS
end
For example.
There no reason why you could not do that. However if you want to print it, you'll probably have to use functions like String#html_safe in rails, or != in haml

Resources