【问题标题】:Interpolation of variables in stored HTML在存储的 HTML 中插入变量
【发布时间】:2017-03-17 15:03:22
【问题描述】:

我正在用 Perl 编写一个 Web 应用程序。它有一个包含联系信息的表单,目前布局如下:

$form_htm = <<EOF
<input value="$in{firstname}" name="firstname">
<input value="$in{surname}" name="surname">
...etc...
EOF

稍后我打印$form_htm(除其他外)以显示网页。

以上内容对我有用,并且字段按预期进行插值。 但是,我希望使用此应用程序的不同组织能够为他们的领域有不同的布局。有些字段不适用于某些组织,有些组织希望字段的大小(在网页上)与其他组织不同。 所以,我想我会将表单的 HTML 存储在数据库中(不同组织的不同记录中的不同版本)。 但是因为 HTML 没有存储在脚本中,字段(如$in{firstname})没有被插入,所以变量名本身最终出现在网页上,(这不是我想要的样子)。

关于我应该如何在这种情况下评估这些变量有什么建议吗? (首先想到的是eval(),但这似乎旨在评估表达式,而不是与许多其他文本混合的变量。)

或者您能否建议一种更好的方法来为不同的组织提供不同的表单布局?

编辑:我也在Perl Monks 上发布了这个问题,但希望得到其他意见。

【问题讨论】:

  • 你想要的叫做模板系统。 Template::Toolkit 是其中之一,但还有很多其他的。以stackoverflow.com/q/14236318/1331451 为例。
  • 另外,您并没有告诉我们您使用的是哪种技术。这是一个带有 CGI.pm 的 CGI 应用程序,还是像 Dancer 应用程序这样更现代的东西?更现代的方法非常适用于模板引擎。
  • 谢谢你,@simbabque。我的应用程序使用了 CGI.pm 和我多年前获得的一些 getcgivars() 子程序。可能应该只是使用其中之一,但还没有整理好。
  • 谢谢@choroba,是的,我在其他地方发布了这个问题,现在我已经在我的原始帖子中添加了更新以反映这一点。

标签: perl


【解决方案1】:

这里有一些不好的方法和一些好的方法来处理这个问题。

坏方法

在代码中粘贴 HTML。

my $form_htm = <<EOF
<input value="$in{firstname}" name="firstname">
<input value="$in{surname}" name="surname">
...etc...
EOF

这是一件很常见的事情。它有很大的问题。首先,它将程序的逻辑与显示的内容结合在一起。要么只有一种方式来显示它,要么你的代码变得越来越复杂,试图允许多种方式来显示它。你遇到了这个问题。

其次,这意味着要改变外观,您需要开发人员参与。您不能让单独的 UX 人员处理 HTML 和 CSS 布局,他们还需要了解 Perl 或让 Perl 开发人员参与其中。这使得进行其他简单的 HTML 更改变得非常昂贵和缓慢。

第三,生成 HTML 的代码散布在它周围,因此很难弄清楚每个页面是如何形成的。如果要更改页面中的表单,则必须在代码中四处寻找它的生成方式。

第四,它很慢。每个页面都必须由服务器生成。

在您的 HTML 中粘贴代码。

<%class>
has 'amount';
has 'name';
</%class>

Dear <% $.name %>,

    We are pleased to inform you that you have won $<% sprintf("%.2f", $.amount) %>!

Sincerely,
The Lottery Commission

<%init>
die "amount must be a positive value!" unless $.amount > 0;
</%init>

这就是 PHP 和 Mason 所做的。 比在代码中粘贴 HTML 更好,但它仍然存在重大问题。它可以很好地使用,但它鼓励你在模板中加入太多的逻辑。这分散了逻辑,使其难以理解正在发生的事情。模板中的代码很难记录和测试。它还将代码混合到模板中,这再次模糊了 UX 人员和开发人员之间的界限。

好方法

MVC:模型-视图-控制器

模型-视图-控制器在数据和逻辑(“模型”)及其显示方式(“视图”)之间提供了清晰的划分。这些与一些代码连接,以从模型中获取数据并将其作为变量(“控制器”)发送到视图。

这是组建网站的最成功的方法之一。 Ruby On Rails 和Catalyst 就是围绕这个构建的。

我推荐Dancer。它比 Catalyst 更小更容易理解。由于它提供的更少,因此更容易调整现有程序以使用它。它提供视图和控制器,模型由你决定。

有两种很好的方式来组合视图。

HTML 模板。

通常的方法是将整个 HTML 页面放在一个模板中,就像我们之前看到的那样,但它没有自己的代码来获取数据,而是传递数据以供使用。它使用有限的语言来处理这些数据。

在 Perl 中,这通常是 Template Toolkit

Dear [% name %],

It has come to our attention that your account is in 
arrears to the sum of [% debt %].

Please settle your account before [% deadline %] or we 
will be forced to revoke your Licence to Thrill.

The Management.

现在用户体验人员可以自行管理 HTML 模板。他们仍然需要学习一种模板语言,但它至少是一种有据可查的语言。有限的语言不鼓励在模板中放置太多代码,从而在视图和其余代码之间创建一种防火墙。

但是格式化模板的所有工作仍然必须在服务器端完成。而且UX人员仍然需要学习一种特殊的模板语言。这给我们带来了最好的方式。

纯 HTML、CSS 和 Javascript。

在这种模式下,HTML 不是在服务器端处理模板并将变量插入其中,而是使用 Javascript 来请求所需的数据并在它认为合适的时候显示它。这有很大的优势。

它将视图与代码的其余部分完全分开。这使 UX 人员可以很好地控制应用程序的行为方式。他们决定每个页面需要什么数据。他们决定如何操作和显示它。开发者可以专注于提供数据。

另一个优点是使用 Javascript。 Javascript 已成为网页设计师必须了解的事实上的编程语言。 UX 人员不需要学习特殊的模板语言,他们使用的 HTML、CSS 和 Javascript 与他们一直使用的相同。

最后,这意味着大部分格式化工作都在客户端完成,从而减少了服务器的负载。

主要缺点是这需要对现有系统进行重大的重新架构。现在,您的服务器代码不再生成 HTML 页面,而是生成 JSON 供 Javascript 通过 REST requests 操作。

混合模板 + Javascript

现有系统的一个很好的混合是使用模板,但不是使用特殊的模板语言,而是使用 Javascript。名称和金额等简单的标量变量仍可作为模板变量提供,但列表和散列等较大的单位作为 JSON 注入模板。

比如这个模板……

var people = [% people %]

将提供people = encode_json(\@people)',它可能会扩展为:

var people = ["Jack", "Jill", "Jane", "Joe"]

然后,UX 人员可以使用这个 Javascript people 数组为所欲为。

不利的一面是,这仍然让开发人员过多地控制网站的工作方式,因为他们决定使用哪些模板以及提供哪些数据,这仍然意味着模板必须在服务器端进行扩展。

从好的方面来说,它允许 UX 人员以他们喜欢的方式操作数据,它强制将视图和其余代码明确分离,并且您可以转换现有代码以使用这些模板一次。

【讨论】:

  • 令人印象深刻的回应,施韦恩!谢谢!我的情况是,我是唯一一个在这个项目上工作的人,而且我并不真正了解 JavaScript。您会建议什么选项以快速轻松地以我的形式工作?我没有使用 Dancer 或类似的。我有类似的东西:
  • @Terry 我建议你学习 Javascript。它现在无处不在,它将非常有用。它与 Perl 并没有太大的不同,基本的数据结构会很熟悉。有tons of tutorials out there。至于“我是唯一参与这个项目的人”,重要的是要让其他人参与这个项目的可能性保持开放。否则,您将始终成为该项目的唯一工作人员。
  • @Terry 最快的方法是用Template Toolkit 替换你的内联HTML。然后看看用 Dancer 之类的东西替换你的路由代码(即“用户要求 search.html,我该怎么做?”)。
  • 模板工具包能否处理这种复杂性: 如果该字段被禁用,则“$dis{}”哈希包含“disabled”,否则为“”。
  • @Terry 是的,这是简单的变量扩展。您可能会反转数据结构,因此传入像 my $vars = { firstname =&gt; { class =&gt; "foo", value =&gt; "bar", is_disabled =&gt; 0 } }; $tt-&gt;process('thing.html', $vars); 这样的散列,模板将类似于 &lt;input class="[% firstname.class %]" value="[% firstname.value %]" maxlength="50" name="firstname" tabindex="2" [% firstname.is_disabled ? "disabled" : "" %]&gt;。我特意从提供的数据中删除了所有 HTML 痕迹。这就是为什么firstname.is_disabled 是布尔值而不是字符串“禁用”的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多