代码之家  ›  专栏  ›  技术社区  ›  Josh Andreas Rehm

使用Ruby,如何确认XML snippit是有效的?

  •  3
  • Josh Andreas Rehm  · 技术社区  · 14 年前

    正如你们中的一些人所知道的,我 working on XMPP (Jabber) integration for the StackOverflow chat system ,作为用Ruby编写的XMPP组件 the xmpp4r package .

    目前有一个问题 :-)我从聊天中获取JSON提要并提取消息的HTML。我在用 The Ruby TidyHTML bindings 要将HTML从JSON fed转换为XHTML,以便我可以将其作为XMPP消息发送——因为XMPP消息只是XML,将HTML转换为XHTML应该使其成为有效的XML,我可以将其粘贴到 <message>

    为了 most messages

    My Mind Is Blown

    不过,对于其他消息,它完全阻塞了——XMPP服务器关闭流,脚本会逐渐停止。(酒馆里的rchenn和其他人很不高兴。嗯,也许不是 沮丧的

    我几乎可以肯定,由于某种原因,消息不是有效的XML,因此XMPP服务器正在关闭连接,因为它在Ruby组件的XML流中遇到了解析错误。下面是这样一条消息的示例:

    <message to='jeswah@smart-safe-secure.com/Token' type='groupchat' xmlns='jabber:client'><body>&lt;div class=&quot;onebox ob-message&quot;&gt;&lt;a class=&quot;roomname&quot; href=&quot;/transcript/message/263372#263372&quot;&gt;&lt;span title=&quot;2010-11-04 19:20:23Z&quot;&gt;1 hour ago&lt;/span&gt;&lt;/a&gt;, by &lt;span class=&quot;user-name&quot;&gt;Fosco&lt;/span&gt; &lt;br/&gt;&lt;div class=&quot;quote&quot;&gt;&lt;div class=&quot;room-mini&quot;&gt;&lt;div class=&quot;room-mini-header&quot;&gt;&lt;h3&gt;&lt;img class=&quot;small-site-logo&quot; title=&quot;Gaming&quot; alt=&quot;Gaming&quot; width=&quot;16&quot; height=&quot;16&quot; src=&quot;http://sstatic.net/gaming/img/favicon.ico&quot; /&gt;&amp;nbsp;&lt;span class=&quot;room-name&quot;&gt;&lt;a href=&quot;http://chat.stackexchange.com/rooms/28/minecraft-talk&quot;&gt;Minecraft Talk&lt;/a&gt;&lt;/span&gt;&lt;/h3&gt;&lt;div class=&quot;room-mini-description&quot;&gt;Everything Minecraft, including classic and survival mode&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;room-current-user-count&quot; title=&quot;current users&quot;&gt;9&lt;/div&gt;&lt;div class=&quot;mspark&quot; style=&quot;height:25px;width:205px&quot;&gt;
    &lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:13px;left:0px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:9px;left:8px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:2px;left:16px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:8px;left:24px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:1px;left:32px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:1px;left:56px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:0px;left:64px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:0px;left:88px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:0px;left:96px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:11px;left:104px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:7px;left:112px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:7px;left:120px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:25px;left:128px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:14px;left:136px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:4px;left:144px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:7px;left:152px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:19px;left:160px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:19px;left:168px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:12px;left:176px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar&quot; style=&quot;width:8px;height:11px;left:184px;&quot;&gt;&lt;/div&gt;&lt;div class=&quot;mspbar now&quot; style=&quot;height:25px;left:154px;&quot;&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;div class=&quot;clear-both&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</body><html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'><div class="onebox ob-message"><a class="roomname" href="/transcript/message/263372#263372"><span title="2010-11-04 19:20:23Z">1 hour ago</span></a>, by <span class="user-name">Fosco</span><br />
    <div class="quote">
    <div class="room-mini"><div class="room-mini-header">
    <h3><img class="small-site-logo" title="Gaming" alt="Gaming" width="16" height="16" src="http://sstatic.net/gaming/img/favicon.ico" />&nbsp;<span class="room-name"><a href="http://chat.stackexchange.com/rooms/28/minecraft-talk">Minecraft Talk</a></span></h3>
    <div class="room-mini-description">Everything Minecraft, including classic and survival mode</div>
    </div>
    <div class="room-current-user-count" title="current users">9</div>
    <div class="mspark" style="height:25px;width:205px">
    <div class="mspbar" style="width:8px;height:13px;left:0px;"></div>
    <div class="mspbar" style="width:8px;height:9px;left:8px;"></div>
    <div class="mspbar" style="width:8px;height:2px;left:16px;"></div>
    <div class="mspbar" style="width:8px;height:8px;left:24px;"></div>
    <div class="mspbar" style="width:8px;height:1px;left:32px;"></div>
    <div class="mspbar" style="width:8px;height:1px;left:56px;"></div>
    <div class="mspbar" style="width:8px;height:0px;left:64px;"></div>
    <div class="mspbar" style="width:8px;height:0px;left:88px;"></div>
    <div class="mspbar" style="width:8px;height:0px;left:96px;"></div>
    <div class="mspbar" style="width:8px;height:11px;left:104px;"></div><div class="mspbar" style="width:8px;height:7px;left:112px;"></div><div class="mspbar" style="width:8px;height:7px;left:120px;"></div><div class="mspbar" style="width:8px;height:25px;left:128px;"></div><div class="mspbar" style="width:8px;height:14px;left:136px;"></div>
    <div class="mspbar" style="width:8px;height:4px;left:144px;"></div>
    <div class="mspbar" style="width:8px;height:7px;left:152px;"></div>
    <div class="mspbar" style="width:8px;height:19px;left:160px;"></div>
    <div class="mspbar" style="width:8px;height:19px;left:168px;"></div><div class="mspbar" style="width:8px;height:12px;left:176px;"></div>
    <div class="mspbar" style="width:8px;height:11px;left:184px;"></div>
    <div class="mspbar now" style="height:25px;left:154px;"></div>
    </div>
    <div class="clear-both"></div>
    </div>
    </div>
    </div>
    </body></html></message>
    

    (此消息碰巧是指向聊天室的单选链接的引述)

    这是鲁比给我的错误:

    IOError: stream closed
    /usr/lib/ruby/1.8/xmpp4r/stream.rb:594:in `empty?'
    /usr/lib/ruby/1.8/rexml/parsers/baseparser.rb:153:in `empty?'
    /usr/lib/ruby/1.8/rexml/parsers/baseparser.rb:193:in `pull'
    /usr/lib/ruby/1.8/rexml/parsers/sax2parser.rb:92:in `parse'
    /usr/lib/ruby/1.8/xmpp4r/streamparser.rb:79:in `parse'
    /usr/lib/ruby/1.8/xmpp4r/stream.rb:75:in `start'
    /usr/lib/ruby/1.8/xmpp4r/stream.rb:72:in `initialize'
    /usr/lib/ruby/1.8/xmpp4r/stream.rb:72:in `new'
    /usr/lib/ruby/1.8/xmpp4r/stream.rb:72:in `start'
    /usr/lib/ruby/1.8/xmpp4r/connection.rb:119:in `start'
    /usr/lib/ruby/1.8/xmpp4r/component.rb:70:in `start'
    /usr/lib/ruby/1.8/xmpp4r/connection.rb:77:in `connect'
    /usr/lib/ruby/1.8/xmpp4r/component.rb:47:in `connect'
    ./classes/SOXMPP_Bridge.rb:20:in `initialize'
    ./soxmpp.rb:81:in `new'
    ./soxmpp.rb:81
    

    最后,我的问题!

    考虑到向XMPP服务器发送无效的XML会让我大吃一惊,有没有办法使用Ruby来验证(而且,最好是, )在将XML发送到XMPP服务器之前?很可能, 修正

    4 回复  |  直到 7 年前
        1
  •  3
  •   Joe Hildebrand    14 年前

    本例中的实际错误是 &nbsp; . 根据 XEP-0071

    XMPP Core的第11.1节规定,除了XML规范第4.6节中定义的五个通用实体(即<、>、&apos;、")之外,字符实体不能通过XML流发送。因此,XHTML-IM的实现不能包含预定义的XHTML 1.0实体(如&nbsp;)——相反,实现必须使用XML规范第4.1节中指定的等效字符引用(即使在诸如“ref”属性中包含的uri等不明显的位置)。

    section 6 .

    简而言之,您需要阅读XEP-0071。

        2
  •  1
  •   Julien Genestoux    14 年前

    Nokogiri 会有帮助吗?然后可以重新序列化XMPP流。 Blather 取代了XMPP4r,DSL也非常棒!

        3
  •  1
  •   Bob Aman    14 年前

    不要用整洁的。使用 HTML5 parser

        4
  •  1
  •   Wayne Conrad    14 年前

    你是在逃避吗?如果是,我会把问题委托给 xmllint ,一个程序,它是 libxml2 . 我使用一个在通过网络发送xml之前生成xml的系统;我们使用xmllint验证我们的xml,如下所示:

        command = "xmllint #{temp_file_path} --schema #{schema_file_path} --noout 2>&1"
        output = `#{command}`
        if $? != 0
          temp_dir.keep
          $stderr.puts "Error validating xml: running command #{command.inspect}"
          $stderr.puts output
          exit(1)
        end
    

    当然,你需要根据自己的情况来调整,但是基本的想法很有效。如果没有DTD,请省略“--schema”位。