`

Nokogiri::XML::Node 方法举例

阅读更多
#=================================================================================
#Here I will discuss several  Nokogiri::XML::Node#methods as in the
documentation
#=================================================================================

#===================================================================================
# Day - I :
# Methods wil be covered:
# #keys,#values,#content=,#set_attribute,#attributes,#content,#delete
#===================================================================================

require "nokogiri"

doc =  Nokogiri::XML('<foo><bar /><foo>', nil, 'EUC-JP')
node =  Nokogiri::XML::Node.new('a',doc) # =>
#<Nokogiri::XML::Element:0x41c8dac name="a">

node.content = "click here"
node.class # => Nokogiri::XML::Element

att = {'href' => "www.example.com","id"=>1425,:class => "dummy"}
att.each {|k,v| node.set_attribute(k,v)}
node.keys # => ["href", "id", "class"]
node.values # => ["www.example.com", "1425", "dummy"]

node.attributes
# => {"href"=>#(Attr:0x41c026a { name = "href", value =
"www.example.com" }),
#     "id"=>#(Attr:0x41c01c0 { name = "id", value = "1425" }),
#     "class"=>#(Attr:0x41c01b6 { name = "class", value = "dummy" })}

node.attributes.map{|k,v| [k,v.class,v.content]}
# => [["href", Nokogiri::XML::Attr, "www.example.com"],
#     ["id", Nokogiri::XML::Attr, "1425"],
#     ["class", Nokogiri::XML::Attr, "dummy"]]

Hash[node.keys.zip(node.values)]
# => {"href"=>"www.example.com", "id"=>"1425", "class"=>"dummy"}
node.content # => "click here"
node.delete "class" # => #<Nokogiri::XML::Attr:0x41c01b6 name="class"
value="dummy">
node.delete("class").class # => NilClass

node.attributes
# => {"href"=>#(Attr:0x41c026a { name = "href", value =
"www.example.com" }),
#     "id"=>#(Attr:0x41c01c0 { name = "id", value = "1425" })}

#===================================================================================
# Day - II :
# Methods wil be covered:
# #to_s,#to_str,#text,#text?
#===================================================================================

doc =  Nokogiri::XML('<foo><bar /><foo>', nil, 'EUC-JP')

node =  Nokogiri::XML::Node.new('a',doc) # =>
#<Nokogiri::XML::Element:0x41d09bc name="a">
node.content = "click here"
node.to_str # => "click here"
node.to_s # => "<a>click here</a>"
node.text # => "click here"
node.children # => [#<Nokogiri::XML::Text:0x41aa69a "click here">]
node.children.class # => Nokogiri::XML::NodeSet
node.children.map(&:text?) # => [true]
node.children.map(&:class) # => [Nokogiri::XML::Text]


node =  Nokogiri::XML::Node.new('title',doc)
node.content = "survey page"
node.to_str # => "survey page"
node.to_s # => "<title>survey page</title>"
node.text # => "survey page"
node.children # => [#<Nokogiri::XML::Text:0x4180ae8 "survey page">]
node.children.class # => Nokogiri::XML::NodeSet
node.children.map(&:class) # => [Nokogiri::XML::Text]

#===================================================================================
# Day - III :
# Methods wil be covered:
# #next,#next_element,#next_sibling,#node_name,#node_name[],#node_type,#
parent
# # parent=
#===================================================================================

require 'nokogiri'

doc = Nokogiri::XML(<<-eohl)
<Stock>
    <Code>7052</Code>
    <Name>PADINI</Name>
    <StockDailyRecords>
        <PriceOpen>1.2</PriceOpen>
        <PriceChange>1.1</PriceChange>
        <PriceClose>10.0</PriceClose>
        <Volume>3000000L</Volume>
    </StockDailyRecords>
    <StockDailyRecords>
        <PriceOpen>1.3</PriceOpen>
        <PriceChange>1.2</PriceChange>
        <PriceClose>11.0</PriceClose>
        <Volume>5000000L</Volume>
    </StockDailyRecords>
</Stock>
eohl
doc
# => #(Document:0x417f634 {
#      name = "document",
#      children = [
#        #(Element:0x417b570 {
#          name = "Stock",
#          children = [
#            #(Text "\n    "),
#            #(Element:0x4179a72 {
#              name = "Code",
#              children = [ #(Text "7052")]
#              }),
#            #(Text "\n    "),
#            #(Element:0x41786cc {
#              name = "Name",
#              children = [ #(Text "PADINI")]
#              }),
#            #(Text "\n    "),
#            #(Element:0x4175d00 {
#              name = "StockDailyRecords",
#              children = [
#                #(Text "\n        "),
#                #(Element:0x41752c4 {
#                  name = "PriceOpen",
#                  children = [ #(Text "1.2")]
#                  }),
#                #(Text "\n        "),
#                #(Element:0x417434c {
#                  name = "PriceChange",
#                  children = [ #(Text "1.1")]
#                  }),
#                #(Text "\n        "),
#                #(Element:0x4170fee {
#                  name = "PriceClose",
#                  children = [ #(Text "10.0")]
#                  }),
#                #(Text "\n        "),
#                #(Element:0x41702b0 {
#                  name = "Volume",
#                  children = [ #(Text "3000000L")]
#                  }),
#                #(Text "\n    ")]
#              }),
#            #(Text "\n    "),
#            #(Element:0x416a5b8 {
#              name = "StockDailyRecords",
#              children = [
#                #(Text "\n        "),
#                #(Element:0x4158ec6 {
#                  name = "PriceOpen",
#                  children = [ #(Text "1.3")]
#                  }),
#                #(Text "\n        "),
#                #(Element:0x414dddc {
#                  name = "PriceChange",
#                  children = [ #(Text "1.2")]
#                  }),
#                #(Text "\n        "),
#                #(Element:0x415e812 {
#                  name = "PriceClose",
#                  children = [ #(Text "11.0")]
#                  }),
#                #(Text "\n        "),
#                #(Element:0x40dfaa8 {
#                  name = "Volume",
#                  children = [ #(Text "5000000L")]
#                  }),
#                #(Text "\n    ")]
#              }),
#            #(Text "\n")]
#          })]
#      })
doc.class # => Nokogiri::XML::Document

doc.css("StockDailyRecords").count # => 2
doc.css("StockDailyRecords").class # => Nokogiri::XML::NodeSet
doc.css("StockDailyRecords").map(&:next)
# => [#(Text "\n    "), #(Text "\n")]
doc.css("StockDailyRecords").map(&:name)
# => ["StockDailyRecords", "StockDailyRecords"]
doc.css("StockDailyRecords").map(&:next_element)
# => [#(Element:0x416a5b8 {
#       name = "StockDailyRecords",
#       children = [
#         #(Text "\n        "),
#         #(Element:0x4158ec6 {
#           name = "PriceOpen",
#           children = [ #(Text "1.3")]
#           }),
#         #(Text "\n        "),
#         #(Element:0x414dddc {
#           name = "PriceChange",
#           children = [ #(Text "1.2")]
#           }),
#         #(Text "\n        "),
#         #(Element:0x415e812 {
#           name = "PriceClose",
#           children = [ #(Text "11.0")]
#           }),
#         #(Text "\n        "),
#         #(Element:0x40dfaa8 {
#           name = "Volume",
#           children = [ #(Text "5000000L")]
#           }),
#         #(Text "\n    ")]
#       }),
#     nil]

doc.at_css("StockDailyRecords").children.map{|el| el.text.strip unless
el.text? }.compact
# => ["1.2", "1.1", "10.0", "3000000L"]
doc.at_css("StockDailyRecords").children.map{|el| el.text.strip if
el.text.strip != "" }.compact
# => ["1.2", "1.1", "10.0", "3000000L"]
doc.at_css("StockDailyRecords").next_sibling # =>
#<Nokogiri::XML::Text:0x416a9fa "\n    ">
doc.at_css("StockDailyRecords").next_sibling.node_name # => "text"

Hash[doc.at_css("StockDailyRecords").children.map {|n|
[n.name,n.node_type]}]
# => {"text"=>3,
#     "PriceOpen"=>1,
#     "PriceChange"=>1,
#     "PriceClose"=>1,
#     "Volume"=>1}
Hash[doc.css("StockDailyRecords").map {|n| [n.name,n.node_type]}]
# => {"StockDailyRecords"=>1}
doc.at_css("StockDailyRecords").children.map {|n|
[n.parent.name,n.name]}
# => [["StockDailyRecords", "text"],
#     ["StockDailyRecords", "PriceOpen"],
#     ["StockDailyRecords", "text"],
#     ["StockDailyRecords", "PriceChange"],
#     ["StockDailyRecords", "text"],
#     ["StockDailyRecords", "PriceClose"],
#     ["StockDailyRecords", "text"],
#     ["StockDailyRecords", "Volume"],
#     ["StockDailyRecords", "text"]]
doc.at_css("StockDailyRecords").children.count
# => 9
doc.root.name # => "Stock"
doc.root.children.map(&:name)
# => ["text",
#     "Code",
#     "text",
#     "Name",
#     "text",
#     "StockDailyRecords",
#     "text",
#     "StockDailyRecords",
#     "text"]
doc.root.children.map{|n| n.name if n.elem? }.compact
# => ["Code", "Name", "StockDailyRecords", "StockDailyRecords"]
doc.root.children.map{|n| n.name if n.elem? && !n.children.empty?
}.compact
# => ["Code", "Name", "StockDailyRecords", "StockDailyRecords"]

#===================================================================================
# Day - IV :
# Methods wil be covered:
# #path,#previous,#previous_element,#pointer_id,#line,#xml?
#===================================================================================

doc = Nokogiri::XML(<<-eohl)
<Stock>
    <Code>7052</Code>
    <Name>PADINI</Name>
    <StockDailyRecords>
        <PriceOpen>1.2</PriceOpen>
        <PriceChange>1.1</PriceChange>
        <PriceClose>10.0</PriceClose>
        <Volume>3000000L</Volume>
    </StockDailyRecords>
    <StockDailyRecords>
        <PriceOpen>1.3</PriceOpen>
        <PriceChange>1.2</PriceChange>
        <PriceClose>11.0</PriceClose>
        <Volume>5000000L</Volume>
    </StockDailyRecords>
</Stock>
eohl

doc.at_css('StockDailyRecords').path
# => "/Stock/StockDailyRecords[1]"
doc.at_css('StockDailyRecords').pointer_id
# => 139602384
doc.at_css('StockDailyRecords').previous.previous
# => #(Element:0x40dd190 { name = "Name", children = [ #(Text "PADINI")]
})
doc.at_css('StockDailyRecords').previous_element
# => #(Element:0x40dd190 { name = "Name", children = [ #(Text "PADINI")]
})
doc.at_css('StockDailyRecords').children[1].path
# => "/Stock/StockDailyRecords[1]/PriceOpen"
doc.at_css('StockDailyRecords').previous_sibling.previous_sibling
# => #(Element:0x40dd190 { name = "Name", children = [ #(Text "PADINI")]
})
doc.at_css('StockDailyRecords').line
# => 4
doc.css('StockDailyRecords').map(&:line)
# => [4, 10]
doc.xml? # => true
#===================================================================================
# Day - V :
# Methods wil be covered:
# #replace,#unlink,#remove
#===================================================================================

doc = Nokogiri::HTML(<<-eohl)
<div>
    <dt>
        Test 1
    </dt>
    <dd>
    </dd>
    <dt>
        Test 2
    </dt>
    <dd>
    foo
    </dd>
</div>
eohl

doc.search('div').children.map(&:name)
# => ["text", "dt", "text", "dd", "text", "dt", "text", "dd", "text"]
doc.at('dt').unlink
doc.search('div').children.map(&:name)
# => ["text", "text", "dd", "text", "dt", "text", "dd", "text"]

node = Nokogiri::XML::Node.new('p',doc)
# => #(Element:0x4d5f3c8 { name = "p" })
doc.at('dt').replace node
doc.search('div').children.map(&:name)
# => ["text", "text", "dd", "text", "p", "text", "dd", "text"]

#===================================================================================
# Day - VI :
# Methods wil be covered:
# #matches?,#css_path,#swap
#===================================================================================

doc = Nokogiri::HTML(<<-eohl)
<div>
    <dt>
        Test 1
    </dt>
    <dd>
    </dd>
    <dt>
        Test 2
    </dt>
    <dd>
    foo
    </dd>
</div>
eohl


doc.search("dt,dd").map{|n| n.name unless n.to_str.strip.empty?
}.compact
# => ["dt", "dt", "dd"]

doc.search("dt,dd").map{|n| n.css_path }
# => ["html > body > div > dt:nth-of-type(1)",
#     "html > body > div > dt:nth-of-type(2)",
#     "html > body > div > dd:nth-of-type(1)",
#     "html > body > div > dd:nth-of-type(2)"]
doc.search("dt,dd").first.matches? "dt:nth-of-type(1)"
# => true

f = Nokogiri::XML.fragment( "<div class='section'><span
class='greeting'></span></div>" )

f.css( 'div' ).each do | node |
  node.swap( '<h1>hi</h1>' )
end

f
# => #(DocumentFragment:0x43aa42c {
#      name = "#document-fragment",
#      children = [
#        #(Element:0x43a3992 { name = "h1", children = [ #(Text "hi")]
})]
#      })

#===================================================================================
# Day - VII :
# Methods wil be covered:
# #traverse
#===================================================================================

doc = Nokogiri::HTML(<<-eofl)
<div id="international-map">
 <div id='a'>
    <a> link a1 </a>
    <a> link a2 </a>
    <a> link a3 </a>
  </div>
  <div id='b'>
       <a> link b1 </a>
       <a> link b2 </a>
  </div>
</div>
eofl

a = []
doc.at('div#a').traverse do |i|
    a << i.text.strip unless i.elem?
end
a.reject(&:empty?) # => ["link a1", "link a2", "link a3"]

doc.at('div#a').traverse do |i|
    p i.text unless i.elem?
end
# >> "\n    "
# >> " link a1 "
# >> "\n    "
# >> " link a2 "
# >> "\n    "
# >> " link a3 "
# >> "\n  "

#===================================================================================
# Day - VIII :
# Methods wil be covered:
# #traverse,#before,#after,#add_previous_sibling,#add_next_sibling
#===================================================================================

doc = Nokogiri::HTML(<<-eofl)
<div id="international-map">
 <div id='a'>
    <a> link a1 </a>
    <a> link a2 </a>
    <a> link a3 </a>
  </div>
  <div id='b'>
       <a> link b1 </a>
       <a> link b2 </a>
  </div>
</div>
eofl

doc.at('div#a').inner_html
# => "\n    <a> link a1 </a>\n    <a> link a2 </a>\n    <a> link a3
</a>\n  "
doc.at('div#a').inner_text
# => "\n     link a1 \n     link a2 \n     link a3 \n  "
doc.at('div#a').internal_subset
# => #(DTD:0x43efa5e { name = "html" })

doc = Nokogiri::HTML::Document.new
doc # => #<Nokogiri::HTML::Document:0x48d2e40 name="document"
children=[#<Nokogiri::XML::DTD:0x48d2c88 name="html">]>
pnode = Nokogiri::XML::Node.new("div",doc)
pnode # => #<Nokogiri::XML::Element:0x48d29a4 name="div">
cnode = pnode.add_child("<p> Welcome </p>")
pnode
# => #(Element:0x48d29a4 {
#      name = "div",
#      children = [
#        #(Element:0x48d26c0 {
#          name = "p",
#          children = [ #(Text " Welcome ")]
#          })]
#      })
#cnode.add_next_sibling("<p> Please come in! </p>")
cnode.class
# => Nokogiri::XML::NodeSet
cnode
# => [#<Nokogiri::XML::Element:0x48d26c0 name="p"
children=[#<Nokogiri::XML::Text:0x48858fc " Welcome ">]>]
cnode[0]
# => #(Element:0x48d26c0 { name = "p", children = [ #(Text " Welcome ")]
})
pnode << cnode[0].add_next_sibling("<p> Please come in! </p>")
pnode
# => #(Element:0x48d29a4 {
#      name = "div",
#      children = [
#        #(Element:0x48d26c0 {
#          name = "p",
#          children = [ #(Text " Welcome ")]
#          }),
#        #(Element:0x4873350 {
#          name = "p",
#          children = [ #(Text " Please come in! ")]
#          })]
#      })
pnode.children.count
# => 2
pnode.children[1].add_previous_sibling("<p> Good morning!!Dear Arjun
</p>")
pnode
# => #(Element:0x48d29a4 {
#      name = "div",
#      children = [
#        #(Element:0x48d26c0 {
#          name = "p",
#          children = [ #(Text " Welcome ")]
#          }),
#        #(Element:0x48700c4 {
#          name = "p",
#          children = [ #(Text " Good morning!!Dear Arjun ")]
#          }),
#        #(Element:0x4873350 {
#          name = "p",
#          children = [ #(Text " Please come in! ")]
#          })]
#      })
pnode.children.count
# => 3

pnode.fragment("<li> Foo </li> <li> bar >/li>")
# => #(DocumentFragment:0x48e73a4 {
#      name = "#document-fragment",
#      children = [
#        #(Element:0x48e72f0 { name = "li", children = [ #(Text " Foo
")] }),
#        #(Text " "),
#        #(Element:0x48e726e {
#          name = "li",
#          children = [ #(Text " bar >/li>")]
#          })]
#      })
pnode.class # => Nokogiri::XML::Element
pnode.child.after("<li> Foo </li> <li> bar >/li>")
# => #(Element:0x48d26c0 { name = "p", children = [ #(Text " Welcome ")]
})
pnode
# => #(Element:0x48d29a4 {
#      name = "div",
#      children = [
#        #(Element:0x48d26c0 {
#          name = "p",
#          children = [ #(Text " Welcome ")]
#          }),
#        #(Element:0x48db180 { name = "li", children = [ #(Text " Foo
")] }),
#        #(Text " "),
#        #(Element:0x48db086 {
#          name = "li",
#          children = [ #(Text " bar >/li>")]
#          }),
#        #(Element:0x48700c4 {
#          name = "p",
#          children = [ #(Text " Good morning!!Dear Arjun ")]
#          }),
#        #(Element:0x4873350 {
#          name = "p",
#          children = [ #(Text " Please come in! ")]
#          })]
#      })
pnode.child.before("<li> Foo </li> <li> bar >/li>")
# => #(Element:0x48d26c0 { name = "p", children = [ #(Text " Welcome ")]
})
pnode
# => #(Element:0x48d29a4 {
#      name = "div",
#      children = [
#        #(Element:0x48a8e2e { name = "li", children = [ #(Text " Foo
")] }),
#        #(Text " "),
#        #(Element:0x48a8c26 {
#          name = "li",
#          children = [ #(Text " bar >/li>")]
#          }),
#        #(Element:0x48d26c0 {
#          name = "p",
#          children = [ #(Text " Welcome ")]
#          }),
#        #(Element:0x48db180 { name = "li", children = [ #(Text " Foo
")] }),
#        #(Text " "),
#        #(Element:0x48db086 {
#          name = "li",
#          children = [ #(Text " bar >/li>")]
#          }),
#        #(Element:0x48700c4 {
#          name = "p",
#          children = [ #(Text " Good morning!!Dear Arjun ")]
#          }),
#        #(Element:0x4873350 {
#          name = "p",
#          children = [ #(Text " Please come in! ")]
#          })]
#      })
1
5
分享到:
评论

相关推荐

    ruby,xml

    5. **XML Schema验证**:如果你有XML Schema(XSD),可以使用Nokogiri的`Nokogiri::XML::Schema`类来验证XML文档是否符合规范: ```ruby schema = Nokogiri::XML::Schema(File.read('your_xml_schema.xsd')) doc...

    nokogiri-signatures:nokogiri 增强以支持 XML 数字签名 (xmldsig)

    Nokogiri::签名 nokogiri 增强功能以​​支持。 进行签名和验证签名的艰苦工作。 这个 gem 提供了一个 nokogiri 友好的界面,用于签署和验证 XML 文档...要签署Nokogiri::XML::Document ,您需要将元素添加到文档中所

    Ruby中使用Nokogiri包来操作XML格式数据的教程

    third_book = Nokogiri::XML::Node.new 'book', doc third_book.content = 'I am the third book' second_book.add_next_sibling third_book ``` 通过这种方式,Nokogiri提供了对XML文档的强大操作能力,包括查找、...

    pugixml读写XML示例

    `xml_document`代表整个XML文档,而`xml_node`表示文档中的一个节点,可以是元素、属性、文本等。 读取XML文件: 1. **初始化pugixml库**:在使用pugixml之前,需要包含头文件`#include &lt;pugixml.hpp&gt;`。 2. **加载...

    rspec-xsd:用于确保 XML 针对给定 XSD 进行验证的 Rspec 匹配器

    RSpec::XSD概述RSpec 匹配器,用于确保针对给定 XSD 验证 XML安装将此行添加到应用程序的 Gemfile 中: group :test do ... 您可以通过传入 Nokogiri::XML::Schema 对象来检查 XML 是否针对给定的架构进行验证 expect

    rlexception: invalid roslaunch xml syntax: no element found: lin

    ### 解决方法 #### 1. 检查文件内容 首先需要确保`.launch`文件不是空文件。可以通过任何文本编辑器打开文件并检查其内容是否存在。 #### 2. 验证 XML 结构 - **确保文件以 `&lt;xml version="1.0"&gt;` 开头**:这是XML...

    ruby操作xml

    - 解析XML:使用`Nokogiri::XML`方法打开一个XML文件,然后可以通过`search`或`at`方法使用XPath或CSS查询文档。 - 修改XML:可以创建新的元素,使用`add_child`方法添加到树中,或者用`content=`设置元素内容。 ...

    nokogiri_bang_finders:将 XML 查找器添加到 Nokogiri,如果未找到任何内容则引发

    这颗宝石说“Nokogiri,如果你找不到我想要的 XML,请大喊大叫。” 例如: doc = Nokogiri :: XML ( "&lt;root&gt;&lt;aliens&gt;&lt;alien&gt;&lt;name&gt;Alf&lt;/name&gt;&lt;/alien&gt;&lt;/aliens&gt;&lt;/root&gt;" ) doc . at ( 'alien' ) . content # =&gt; ...

    用ruby读excel文件生成xml文件

    xml = Nokogiri::XML::Builder.new do |xml| xml.root { |root| data.each do |row| root.row do |row_node| row.each { |key, value| row_node.send(key.to_s.downcase, value) } end end } end ``` 最后,...

    XML:Raku的面向对象的XML库

    它支持每种主要的XML节点(XML :: Node): 文件(XML :: Document) 元素(XML :: Element) 文字(XML :: Text) 评论(XML :: Comment) PI(XML :: PI) CDATA(XML :: CDATA) 您可以通过在字符串上下文中使用...

    pugixml 一个很好用的XML类

    root.append_child("child1").append_child(pugi::node_pcdata).set_value("Text1"); if (!doc.save_file("test.xml")) { std::cout !" &lt;&lt; std::endl; return 1; } return 0; } ``` 这段代码首先创建了一个...

    Delphi向XML中添加节点数据.rar

     iXml: IDOMDocument;  iRoot, iNode, iNode2, iChild, iAttribute: IDOMNode;  begin  XMLDocument1.Active := False;  XMLDocument1.XML.Text := '';  XMLDocument1.Active := True;  iXml := XMLDocument1...

    delphi解析xml文件实例

    使用`LoadFromFile`方法加载XML文件到TXMLDocument对象中。 3. **遍历XML节点**: TXMLDocument对象的根节点是XML文档的`&lt;document&gt;`元素。我们可以使用`ChildNodes`属性访问这些子节点。例如,要获取第一个子...

    pugixml-1.0

    **Pugixml-1.0:高效且易用的XML解析库** Pugixml是一个轻量级、高性能的C++库,专门用于XML文档的解析和操作。...通过熟悉这些基本概念和使用方法,开发者可以快速上手并充分利用这个库来解析和操作XML数据。

    XMLDOM对象方法手册

    - `transformNode`: 应用XSLT转换到XML文档。 - `validateOnParse`: 设置是否在加载XML时进行验证。 - `resolveExternals`: 设置是否在加载XML时解析外部实体。 6. **XPath查询** XPath是一种在XML文档中查找...

    Node.js实现的XML文件提取内容并转换为TXT

    2. **读取文件**:Node.js的内置`fs`模块提供了读取文件的能力。可以使用`fs.readdirSync()`遍历指定目录及子目录下的所有文件,获取到XML文件的路径。 3. **递归遍历目录**:由于题目要求处理嵌套目录下的所有XML...

    Ruby的XML格式数据解析库Nokogiri的使用进阶

    ### Ruby的XML格式数据解析库Nokogiri的使用进阶 #### 一、Nokogiri概述 Nokogiri是Ruby中的一个强大的XML/HTML解析器,它提供了多种方式来解析、搜索和修改XML/HTML文档。Nokogiri能够与标准库一样方便地操作文档...

Global site tag (gtag.js) - Google Analytics