我目前正在重写一个 PHP 类,该类试图将 XML 文件拆分成更小的 block ,以使用 XMLReader 和 XMLWriter 而不是当前的基本文件系统和正则表达式方法。
但是,我不知道如何从 XML 序言中获取版本、编码和独立标志。
我的测试 XML 文件的开头如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fakedoctype SYSTEM "fake_doc_type.dtd">
<!--
This is a comment, it's here to try and get the parser to break in some way
-->
<root attribute="value" otherattribute="othervalue">
我可以让读者打开它并使用 read()、next() 等浏览文档,但我似乎无法获得 <?xml ... ?> 中的任何内容。 .我能够访问的第一件事是伪造的 DOCTYPE。
我的测试代码如下:
$a = new XMLReader ();
var_dump ($a -> open ('/path/to/test/file.xml')) // true
var_dump ($a -> nodeType); // 0
var_dump ($a -> name); // ""
var_dump ($a -> readOuterXML ()); // ''
var_dump ($a -> read ()); // true
var_dump ($a -> nodeType); // 10
var_dump ($a -> readOuterXML ()); // <!DOCTYPE fakedoctype SYSTEM "fake_doc_type.dtd">
当然,我总是可以假设 XML 1.0,编码为 UTF8 和独立 = 是,但为了正确性,我真的更愿意能够获取我的源提要中的值并在生成拆分时使用它们文件。
关于 XMLReader 和 XMLwriter 的文档似乎很差,所以我很有可能错过了文档中的某些内容。有谁知道在这种情况下该怎么办?
最佳答案
我从 XMLReader 知道的,即使它有 XMLReader::XML_DECLARATION 常量,我在使用 XMLReader::read( ) 在 XMLReader::$nodeType 属性中。
看起来它被跳过了,我也想知道为什么会这样,我还没有找到任何标志或选项来改变这种行为。
对于输出,XMLReader 总是返回 UTF-8 编码的字符串。这与 PHP 中其他基于 libxml 的部分相同。所以从那方面来说,一切都很清楚。但我认为这不是您感兴趣的部分,而是您使用 XMLReader::open() 打开的文件中输入的具体字符串。
不是专门针对 XMLReader 我曾经创建过 a utility class I named XMLRecoder它能够根据 XML 声明和 BOM 检测 XML 字符串的编码。我认为你应该两者都做。这是我认为您仍然需要使用正则表达式的一部分,但因为 XML 声明必须是第一件事,而且它是一个处理指令 (PI),即 very well and strict defined。你应该可以看到里面的内容。
这是 XMLRecoder 代码中的一些相关部分:
### excerpt from https://gist.github.com/hakre/5194634
/**
* pcre pattern to access EncodingDecl, see <http://www.w3.org/TR/REC-xml/#sec-prolog-dtd>
*/
const DECL_PATTERN = '(^<\?xml\s+version\s*=\s*(["\'])(1\.\d+)\1\s+encoding\s*=\s*(["\'])(((?!\3).)*)\3)';
const DECL_ENC_GROUP = 4;
const ENC_PATTERN = '(^[A-Za-z][A-Za-z0-9._-]*$)';
...
($result = preg_match(self::DECL_PATTERN, $buffer, $matches, PREG_OFFSET_CAPTURE))
&& $result = $matches[self::DECL_ENC_GROUP];
如上图所示,它一直持续到编码,所以还不完整。但是,对于提取编码的需要(以及您需要的版本),它应该可以完成工作。我已针对大量(数千)随机 XML 文档运行此程序以进行测试。
另一部分是BOM检测:
### excerpt from https://gist.github.com/hakre/5194634
const BOM_UTF_8 = "\xEF\xBB\xBF";
const BOM_UTF_32LE = "\xFF\xFE\x00\x00";
const BOM_UTF_16LE = "\xFF\xFE";
const BOM_UTF_32BE = "\x00\x00\xFE\xFF";
const BOM_UTF_16BE = "\xFE\xFF";
...
/**
* @param string $string string (recommended length 4 characters/octets)
* @param string $default (optional) if none detected what to return
* @return string Encoding, if it can not be detected defaults $default (NULL)
* @throws InvalidArgumentException
*/
public function detectEncodingViaBom($string, $default = NULL)
{
$len = strlen($string);
if ($len > 4) {
$string = substr($string, 0, 4);
} elseif ($len < 4) {
throw new InvalidArgumentException(sprintf("Need at least four characters, %d given.", $len));
}
switch (true) {
case $string === self::BOM_UTF_16BE . $string[2] . $string[3]:
return "UTF-16BE";
case $string === self::BOM_UTF_8 . $string[3]:
return "UTF-8";
case $string === self::BOM_UTF_32LE:
return "UTF-32LE";
case $string === self::BOM_UTF_16LE . $string[2] . $string[3]:
return "UTF-16LE";
case $string === self::BOM_UTF_32BE:
return "UTF-32BE";
}
return $default;
}
对于 BOM 检测,我也确实针对同一组 XML 文档运行了它,但是,使用 BOM 的并不多。如您所见,检测顺序针对更常见的场景进行了优化,同时处理了不同 BOM 之间的重复二进制模式。我遇到的大多数文档都没有 BOM,您主要需要它来确定文档是否为 UTF-32 编码。
希望这至少能提供一些见解。
关于PHP XMLReader,获取版本和编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15477999/
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我正在使用ruby1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit