dracoblue / craur
无损 XML 到 JSON 和 JSON 到 XML 转换器(以及 CSV/xlsx/yaml)。轻松编写 PHP Json/Xml/Csv/Yaml/excel 导入器
Requires
- php: ^7.2 || ^8.0
- phpoffice/phpspreadsheet: ^1.12
- symfony/yaml: ^2.0 || ^3.0 || ^4.0
Requires (Dev)
- dracoblue/naith: ^1.1
README
craur 库有两个主要目的
- 使编写 Xml/Json 导入器非常方便(查询多个元素或恰好一个元素)
- 实现一种规范,将 XML 转换为 JSON 而不丢失任何信息
纯 JSON 有什么问题?
JSON 没有问题。但看看这个例子
item = {
"link": "http://example.org"
}
如果你要查询链接,你这样做: item.link
。但如果可能有多个链接呢?就像这样
item = {
"link": ["http://example.org", "http://subdomain.example.org"]
}
现在你必须使用 item.link[0]
来查询第一个。如果你将 XML 编程性转换为 JSON,你无法确定它的意思。
使用 craur 查询这个值看起来像这样
$craur_node->get('item.link') // gets: "http://example.org"
如果你想得到一个数组,你这样做
$craur_node->get('item.link[]') // gets: ["http://example.org", "http://subdomain.example.org"]
对于 craur 来说,你是否有数组或简单对象无关紧要。这两个调用都会工作。
你甚至可以定义一个默认值,以防该属性是可选的
$craur_node->get('item.description', 'Default Text!') // returns 'Default Text!'
PHP 例子
这个例子展示了如果你使用 craur 解析一个简单的 atom-feed 会是什么样子。
$craur_node = Craur::createFromXml($xml_string);
var_dump($craur_node->get('feed.@xmlns')); // http://www.w3.org/2005/Atom
foreach ($craur_node->get('feed.entry.link[]') as $link) {
var_dump($link->get('@href'));
}
如果你想看更多例子,请查看 php/tests/
文件夹。它包含很多例子。
测试
你可以使用以下命令运行测试
make test
测试位于 php/tests/
。测试需要安装并激活 xdebug
。成功的测试必须有 100% 代码覆盖率。
持续测试
如果你已经安装了 inotifywait
[linux, apt-get install inotify-tools] 或 wait_on
[macosx, port install wait_on],你可以使用
make test-constant
这将使测试在文件更改时运行。如果你想要持续测试,这非常有帮助。
API
Craur::createFromJson($json_string
) : Craur
将为给定的 JSON 字符串创建并返回一个新的 craur 实例。
$node = Craur::createFromJson('{"book": {"authors": ["Hans", "Paul"]}}');
$authors = $node->get('book.authors[]');
assert(count($authors) == 2);
Craur::createFromXml($xml_string[, $encoding = 'utf-8']) :
Craur`
将为给定的 XML 字符串创建并返回一个新的 craur 实例。
$node = Craur::createFromXml('<book><author>Hans</author><author>Paul</author></book>');
$authors = $node->get('book.author[]');
assert(count($authors) == 2);
Craur::createFromHtml($html_string[, $encoding = 'utf-8']) :
Craur`
将为给定的 HTML 字符串创建并返回一个新的 craur 实例。
$node = Craur::createFromHtml('<html><head><title>Hans</title></head><body>Paul</body></html>');
assert($node->get('html.head.title') == 'Hans');
assert($node->get('html.body') == 'Paul');
Craur::createFromCsvFile($file_path, array $field_mappings, $delimiter = ';'
) : Craur
将加载 CSV 文件,并根据给定的 $field_mappings
填充对象。
/*
* If the file loooks like this:
* Book Name;Book Year;Author Name
* My Book;2012;Hans
* My Book;2012;Paul
* My second Book;2010;Erwin
*/
$shelf = Craur::createFromCsvFile('fixtures/books.csv', array(
'book[].name',
'book[].year',
'book[].author[].name',
));
assert(count($shelf->get('book[]')) === 2);
foreach ($shelf->get('book[]') as $book)
{
assert(in_array($book->get('name'), array('My Book', 'My second Book')));
foreach ($book->get('author[]') as $author)
{
assert(in_array($author->get('name'), array('Hans', 'Paul', 'Erwin')));
}
}
Craur::createFromExcelFile($file_path, array $field_mappings
) : Craur
将加载 Excel 文件的第一张表,并根据给定的 $field_mappings
填充对象。
/*
* If the file loooks like this:
* Book Name;Book Year;Author Name
* My Book;2012;Hans
* My Book;2012;Paul
* My second Book;2010;Erwin
*/
$shelf = Craur::createFromExcelFile('fixtures/books.xlsx', array(
'book[].name',
'book[].year',
'book[].author[].name',
));
assert(count($shelf->get('book[]')) === 2);
foreach ($shelf->get('book[]') as $book)
{
assert(in_array($book->get('name'), array('My Book', 'My second Book')));
foreach ($book->get('author[]') as $author)
{
assert(in_array($author->get('name'), array('Hans', 'Paul', 'Erwin')));
}
}
Craur::createFromYamlFile($file_path
) : Craur
将为给定的 YAML 文件路径创建并返回一个新的 craur 实例。
* If the file loooks like this:
* books:
* -
* name: My Book
* year: 2012
* authors:
* -
* name: Hans
* age: 32
* -
* name: Paul
* age: 20
* -
* name: My second Book
* authors:
* name: Erwin
* age: 10
*/
$shelf = Craur::createFromYamlFile('fixtures/books.yaml', array());
assert(count($shelf->get('books[]')) === 2);
foreach ($shelf->get('books[]') as $book)
{
assert(in_array($book->get('name'), array('My Book', 'My second Book')));
foreach ($book->get('authors[]') as $author)
{
assert(in_array($author->get('name'), array('Hans', 'Paul', 'Erwin')));
}
}
Craur#get($path[, $default_value]
) : Craur
|mixed
返回对象中给定路径的值。如果给定的路径不存在且已显式设置 $default_value
:将返回 $default_value
。
$node = Craur::createFromJson('{"book": {"name": "MyBook", "authors": ["Hans", "Paul"]}}');
$book = $node->get('book');
assert($book->get('name') == 'MyBook');
assert($book->get('price', 20) == 20);
$authors = $node->get('book.authors[]');
assert(count($authors) == 2);
自2.1.0版本起,可以通过在点之前使用反斜杠(\)来转义路径参数中的点(例如,如果键包含点)。
$node = Craur::createFromJson('{"http://example.org": {"name": "Example Site"}}');
$book = $node->get('http://example\.org');
assert($book->get('name') == 'MyBook');
如果需要转义反斜杠(\),也使用反斜杠。
$node = Craur::createFromJson('{"http://example\\\\.org": {"name": "Example Site"}}');
$book = $node->get('http://example\\\\\\.org');
assert($book->get('name') == 'Example Site');
Craur#getWithFilter($path, $filter[, $default_value]
) : Craur
|mixed
$path, $filter[, $default_value]
) : Craur
|mixed
与 Craur#get
类似,但可以使用可调用的对象作为过滤器。在返回值之前,函数将评估 $filter($value)
并返回此值。
$node = Craur::createFromJson('{"book": {"name": "MyBook", "authors": ["Hans", "Paul"]}}');
$book = $node->get('book');
assert($book->get('name') == 'MyBook');
assert($book->get('price', 20) == 20);
$authors = $node->get('book.authors[]');
assert(count($authors) == 2);
过滤器还可以抛出异常以隐藏结果集中的值
function isACheapBook(Craur $value)
{
if ($value->get('price') > 20)
{
throw new Exception('Is no cheap book!');
}
return $value;
}
$node = Craur::createFromJson('{"books": [{"name":"A", "price": 30}, {"name": "B", "price": 10}, {"name": "C", "price": 15}]}');
$cheap_books = $node->getWithFilter('books[]', 'isACheapBook');
assert(count($cheap_books) == 2);
assert($cheap_books[0]->get('name') == 'B');
assert($cheap_books[1]->get('name') == 'C');
Craur#getValues(array $paths_map[, array $default_values, $default_value]
) : mixed[]
array $paths_map[, array $default_values, $default_value]
) : mixed[]
一次返回多个值。如果给定的路径未设置,可以使用 $default_values
数组来指定默认值。如果路径未设置且未提供默认值,将抛出异常。如果您希望即使路径在 $default_values
中不存在,也要有默认值,可以使用 $default_value
。
$node = Craur::createFromJson('{"book": {"name": "MyBook", "authors": ["Hans", "Paul"]}}');
$values = $node->getValues(
array(
'name' => 'book.name',
'book_price' => 'price',
'first_author' => 'book.authors'
),
array(
'book_price' => 20
)
);
assert($values['name'] == 'MyBook');
assert($values['book_price'] == '20');
assert($values['first_author'] == 'Hans');
Craur#getValuesWithFilters(array $paths_map, array $filters [, array $default_values, $default_value]
) : mixed[]
array $paths_map, array $filters [, array $default_values, $default_value]
) : mixed[]
与 Craur#getValues
类似,但允许为 $path_map
中的每个键设置过滤器。
$node = Craur::createFromJson('{"book": {"name": "MyBook", "authors": ["Hans", "Paul"]}}');
$values = $node->getValuesWithFilters(
array(
'name' => 'book.name',
'book_price' => 'price',
'first_author' => 'book.authors'
),
array(
'first_author' => 'strtoupper',
'name' => 'strtolower'
),
array(
'book_price' => 20
)
);
assert($values['name'] == 'MyBook');
assert($values['book_price'] == '20');
assert($values['first_author'] == 'HANS');
Craur#toJsonString() : String
String
将对象作为JSON字符串返回。可以从 Craur::createFromJson
加载。
Craur#toXmlString() : String
String
将对象作为XML字符串返回。可以从 Craur::createFromXml
加载。
Craur#saveToCsvFile($file_path, array $field_mappings, $delimiter=';'
) : void
$file_path, array $field_mappings, $delimiter=';'
) : void
将对象内容存储为csv文件,根据给定的 $field_mappings
。该文件可以用 Craur::loadFromCsvFile
加载,并使用相同的 $field_mappings
。
$data = array(
'book' => array(
array(
'name' => 'My Book',
'year' => '2012',
'author' => array(
array('name' => 'Hans'),
array('name' => 'Paul')
)
),
array(
'name' => 'My second Book',
'year' => '2010',
'author' => array(
array('name' => 'Erwin')
)
)
)
);
$shelf = new Craur($data);
$shelf->saveToCsvFile('fixtures/temp_csv_file.csv', array(
'book[].name',
'book[].year',
'book[].author[].name',
));
csv文件现在看起来像这样
book[].name;book[].year;book[].author[].name
"My Book";2012;Hans
"My Book";2012;Paul
"My second Book";2010;Erwin
Craur#writeToCsvFileHandle($file_handle, array $field_mappings, $delimiter = ';'
) : void
$file_handle, array $field_mappings, $delimiter = ';'
) : void
将对象内容写入给定的文件句柄,根据给定的 $field_mappings
。如果要将csv内容输出到控制台,请使用 STDOUT
常量作为 $file_handle
。此方法由 Craur#saveToCsvFile
使用。
$data = array(
'book' => array(
array(
'name' => 'My Book',
'year' => '2012',
'author' => array(
array('name' => 'Hans'),
array('name' => 'Paul')
)
),
array(
'name' => 'My second Book',
'year' => '2010',
'author' => array(
array('name' => 'Erwin')
)
)
)
);
$shelf = new Craur($data);
$shelf->writeToCsvFileHandle(STDOUT, array(
'book[].name',
'book[].year',
'book[].author[].name',
));
// will echo:
// "My Book";2012;Hans
// "My Book";2012;Paul
// "My second Book";2010;Erwin
Cli
自1.5.0版本起,您也可以在命令行上使用craur。只需将任何内容管道到craur二进制文件,即可获取内容作为json、xml或csv。
示例(xml转换为json)
$ cat php/tests/fixtures/example_atom_feed.xml | php/craur --output_format json
示例(xml转换为csv,带有字段映射 - 有关更多详细信息,请参阅 --output_format
)
$ cat php/tests/fixtures/example_atom_feed.xml | php/craur --output_format csv feed.link[].@rel feed.link[].@href
// output:
alternate;http://example.org/
self;http://example.org/feed.atom
输入格式 --input_format [json|xml|csv|auto]
指定输入格式。默认为自动。
对于输入格式 csv
,您可以通过传递选项 --csv_input_delimiter
来更改分隔符
带有 --csv_input_delimiter
的示例
$ cat php/tests/fixtures/books_comma_separated.csv | php/craur --input_format csv --csv_input_delimiter , --output_format json feed.link[].@rel feed.link[].@href
输出格式 --output_format [json|xml|csv]
指定输出格式。
示例(xml转换为json)
$ cat php/tests/fixtures/example_atom_feed.xml | php/craur --output_format json
// output:
// ... lots of json ...
如果您指定了输出格式为 csv
,则必须以参数形式提供字段映射。要获取feed链接元素的rel属性和href属性的所有rel-属性和href-属性,可以这样做
$ cat php/tests/fixtures/example_atom_feed.xml | php/craur --output_format csv feed.link[].@rel feed.link[].@href
// output:
alternate;http://example.org/
self;http://example.org/feed.atom
此外,您还可以通过传递选项 --csv_output_delimiter
来指定csv分隔符
$ cat php/tests/fixtures/example_atom_feed.xml | php/craur --output_format csv --csv_output_delimiter , feed.link[].@rel feed.link[].@href
// output:
alternate,http://example.org/
self,http://example.org/feed.atom
变更日志
- 3.1.0 (2022/12/06)
- 添加了覆盖csv分隔符的可能性
- 3.0.1 (2022/12/02)
- 放弃使用Travis CI,转而使用GitHub Actions
- 将php 8.1+8.2添加到测试矩阵中
- 3.0.0 (2020/10/22)
- 将
dracoblue/naith
移动为开发依赖项 - 放弃使用
phpoffice/phpexcel
,转而使用phpoffice/phpspreadsheet
- 放弃对
PHP 5
、PHP 7.0
和PHP 7.1
的支持
- 将
- 2.1.1 (2017/12/12)
- 添加了对symfony/yaml 4.x的兼容性
- 2.1.0 (2017/03/13)
- 添加了在路径中转义点的兼容性
- 2.0.1 (2016/06/28)
- 添加了对symfony/yaml 3.x的兼容性
- 2.0.0 (2015/04/28)
- BC:如果xml标签只有属性,则
__toString
返回空字符串 - 之前会抛出致命错误
- BC:如果xml标签只有属性,则
- 1.8.2 (2015/03/17)
- 将phpexcel降级到
1.7.8
(而不是1.8.0)
- 将phpexcel降级到
- 1.8.1 (2015/03/17)
- 已切换到
phpoffice/phpexcel
,因为codeplex/phpexcel
已被弃用
- 已切换到
- 1.8.0 (2014/07/19)
- 添加了对 html5 标签的支持(通过简单地忽略所有意外的标签) #24
- 1.7.4 (2013/06/28)
- 值为 0 的 xml 文件不工作
- 调用类作为过滤器不工作
- 1.7.3 (2013/06/10)
- 使用 composer 包管理 phpexcel 而不是自定义 pearplex 仓库
- 1.7.2 (2013/06/10)
- 添加了 composer 包信息
- 将文件从 php/ 移动到 src/
- 将测试从 php/tests 移动到 tests/
- 将 craur 从 php/craur 移动到 bin/craur
- 重命名从 .class.php 到 .php
- 1.7.1 (2013/02/05)
- 对空 xml 字符串抛出异常(修复了 #14)
- 1.7.0 (2012/09/22)
- 在 composer.json 中排除了 naith
- 添加了 composer.json 以进行依赖管理
- 添加了
Craur::createFromExcelFile($file_path, array $field_mappings)
- 添加了
Craur::createFromYamlFile($file_path)
- 1.6.0 (2012/08/07)
- 添加 html 作为 craur 命令行的输入格式
- 添加了加载 html 片段的可能性(破坏性更改:片段不再创建 html.body 模板)
- 1.5.3 (2012/04/16)
- 添加了
Craur::createFromHtml($html_string, $encoding = 'utf-8')
- 添加了
- 1.5.2 (2012/04/12)
- 在 createFromXml 中去除无效的 utf8 字符
- 为 createFromXml 添加了编码参数
- 1.5.1 (2012/04/05)
- 允许多列具有相同的 csv 映射
- 1.5.0 (2012/04/02)
- 为 craur 添加了命令行界面
- 添加了
saveToCsvFile($file_path, array $field_mappings)
- 添加了
writeToCsvFileHandle($file_handle, array $field_mappings)
- 修复了 csv 文件测试
- 只添加非空的 csv 值
- 添加了从对象生成 csv 行的方法
- 将 naith 作为测试框架捆绑(https://github.com/DracoBlue/naith)
- 允许在存在空隙的情况下进行 csv 字段映射(例如,feed[] 和 feed[].entry.categories[] 现在可以工作)
- 修复了具有标量子值的导入映射(例如,issues[].tag[])
- 1.4.1 (2012/03/14)
- 添加了
make test-constant
(在 Linux 上使用 inotifywait 或在 mac osx 上使用 wait_on 监视文件更改,并在更改时运行测试)
- 添加了
- 1.4.0 (2012/03/14)
- 添加了
Craur::createFromCsvFile($file_path, array $field_mappings)
- 添加了
- 1.3.0 (2012/03/09)
- 添加了
getWithFilter($path, Callable $filter[, $default_value])
- 添加了
getValuesWithFilters($path, array $filters[, array $default_values, $default_value])
- 将引导文件添加到所有测试文件之前
- 在代码覆盖率中忽略测试文件本身
- 添加了
- 1.2.0 (2012/03/06)
- 为 Craur#get 添加了额外的可选参数
$default_value
- 添加了测试的最低代码覆盖率,以确保成功构建
- 也可以用纯 PHP 数组初始化 Craur
- 添加了代码覆盖率的文本摘要
- 添加了(已禁用)实验性的对 clover.xml 代码覆盖率文件的支持
- 为 Craur#get 添加了额外的可选参数
- 1.1.0 (2012/03/06)
- 在失败的断言或异常的情况下抛出致命错误
- 在无效的 json 上抛出错误
- 1.0.0 (2012/03/05)
- 添加了大量的 phpdoc
- Makefile 使用 ./run_tests.sh 包装器,如果其中一个测试失败,将正确地失败
- 现在可以检索第一个数组元素的值
- Craur#get 现在也返回关联数组作为新的 Craur-对象,而不是失败
- 添加了 bootstrap_for_test.php,因此我们可以正确地失败在警告/断言上
- 为 Craur# 添加了 getValues 以返回多个路径
- 将测试拆分为单独的文件
- 添加了 Makefile(使用
make test
执行测试) - 为
Craur->get($path, $default_value)
添加了默认值 - 初始版本
许可证
本作品由 DracoBlue(http://dracoblue.net)版权所有,并按 MIT 许可协议许可。