在Jekyll模板中包含外部文件

时间:2013-02-19 13:07:20

标签: ruby jekyll jekyll-extensions

是否可以在Jekyll模板中包含来自其他域的html文件?如果是这样,语法是什么?

我不是Ruby或Jekyll开发人员,或多或少代表另一个人请求,如果答案显而易见,请原谅我!至少我在初步研究中找不到答案。

本质上我们试图从另一个域中提取页脚的标记,这就是生产将如何工作所以我们实际上只是试图在我们的模板交付中模拟它。

干杯

2 个答案:

答案 0 :(得分:2)

您无法在模板内执行此操作。但是,您可以定义一个自定义Liquid标签,用于擦除远程页面的标记,然后将该标记放入模板中。这将在一个名为例如plugins/remote_footer.rb

require 'nokogiri'
require 'open-uri'
require 'uri'

module Jekyll

  class RemoteFooterTag < Liquid::Tag

    def initialize(tag_name, markup, tokens)
      #markup is what is defined in the tag. Lets make it a URL so devs 
      #don't have to update code if the URL changes.
      url = markup

      #check if the URL is valid
      if url =~ URI::regexp
        #grab the remote document with nokogiri
        doc = Nokogiri::HTML(open(url))

        #search the document for the HTML element you want
        @node = doc.at_xpath("//div[@id='footer']")
      else
        raise 'Invalid URL passed to RemoteFooterTag'
      end

      super
    end

    def render(context)
      output = super
      if @node 
        node.to_s
      else
        "Something went wrong in RemoteFooterTag"
      end
    end
  end
end

Liquid::Template.register_tag('remote_footer', Jekyll::RemoteFooterTag)

然后在你的模板中:

{% remote_footer http://google.com %}

我把它快速地扔在一起,并没有检查它是否运行,但希望它足以与之合作。请记住,当液体分析器在页面上运行时,这将运行一次,如果远程元素发生更改,则在重建Jekyll站点之前不会反映该内容。

答案 1 :(得分:2)

我只是偶然发现了这个问题,我找不到任何解决我所有用例的工作解决方案,所以我编写了自己的插件。

N.B。这是我写过的第一首红宝石。

require 'nokogiri'
require 'open-uri'
require 'uri'

class Jekyll::IncludeRemoteTag < Jekyll::Tags::IncludeTag
  @@remote_cache = {}

  def initialize(tag_name, markup, tokens)
    super
    @url = @file
  end

  def validate_url(url)
    if url !~ URI::regexp
      raise ArgumentError.new <<-eos
Invalid syntax for include_remote tag. URL contains invalid characters or sequences:

#{url}

Valid syntax:

#{syntax_example}

eos
    end
  end

  def syntax_example
    "{% #{@tag_name} http://domain.ltd css=\".menu\" xpath=\"//div[@class='.menu']\" param=\"value\" param2=\"value\" %}"
  end

  def render(context)
    @url = render_variable(context) || @url
    validate_url(@url)

    if @params
      validate_params
      @params = parse_params(context)
    end

    xpath = @params['xpath']
    css = @params['css']

    if ! html = @@remote_cache["#{@url}_#{xpath}"]
      # fetch remote file
      page = Nokogiri::HTML(open(@url))

      # parse extract xpath/css fragments if necessary
      node = page.at_xpath(xpath) if xpath
      node = page.css(css) if css
      node = page if !node

      raise IOError.new "Error while parsing remote file '#{@url}': '#{xpath||css}' not found" if !node

      # cache result
      html = @@remote_cache["#{@url}_#{xpath}"] = node.to_s
    end

    begin
      partial = Liquid::Template.parse(html)

      context.stack do
        context['include'] = @params
        partial.render!(context)
      end
    rescue => e
      raise Jekyll::Tags::IncludeTagError.new e.message, @url
    end
  end
end

Liquid::Template.register_tag('include_remote', Jekyll::IncludeRemoteTag)

你会像这样使用它:

<!-- fetch header.html -->
{% assign url = 'http://mything.me/_includes/header.html' %}
{% include_remote {{ url }} %}

<!-- fetch menu.html and extract div.menu -->
{% include_remote 'http://mything.me/_includes/menu.html' css="div.menu" links=site.data.menu %}

<!-- fetch menu.html and extract div.menu (xpath version) -->
{% include_remote 'http://mything.me/_includes/menu.html' xpath="div[@class='menu']" links=site.data.menu %}

它基本上与普通的包含文件完全相同,但它是远程的。

可从此处下载:https://gist.github.com/kilianc/a6d87879735d4a68b34f

MIT许可证。

相关问题