我对解析XML文件相对较新,并且正在尝试使用XMLReader读取大型XML文件。
<?xml version="1.0" encoding="UTF-8"?>
<ShowVehicleRemarketing environment="Production" lang="en-CA" release="8.1-Lite" xsi:schemaLocation="http://www.starstandards.org/STAR /STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd">
<ApplicationArea>
<Sender>
<Component>Component</Component>
<Task>Task</Task>
<ReferenceId>w5/cron</ReferenceId>
<CreatorNameCode>CreatorNameCode</CreatorNameCode>
<SenderNameCode>SenderNameCode</SenderNameCode>
<SenderURI>http://www.example.com</SenderURI>
<Language>en-CA</Language>
<ServiceId>ServiceId</ServiceId>
</Sender>
<CreationDateTime>CreationDateTime</CreationDateTime>
<Destination>
<DestinationNameCode>example</DestinationNameCode>
</Destination>
</ApplicationArea>
...
我收到以下错误
ErrorException [Warning]:XMLReader :: read()[xmlreader.read]:compress.zlib:// D:/WebDev/example/local/public/../upload/example.xml.gz:2:名称空间错误:未定义ShowVehicleRemarketing上schemaLocation的名称空间前缀xsi
我一直在搜索并找不到有关使用XMLReader读取带有命名空间的XML文件的有用信息 - 我如何定义命名空间,如果这实际上是我需要做的事情......很少帮助?链接到相关资源?
答案 0 :(得分:5)
需要定义xsi
命名空间。 E.g。
<ShowVehicleRemarketing
environment="Production"
lang="en-CA"
release="8.1-Lite"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.starstandards.org/STAR/STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd"
>
更新:您可以write a user defined filter然后让XMLReader use that filter,例如:
stream_filter_register('darn', 'DarnFilter');
$src = 'php://filter/read=darn/resource=compress.zlib://something.xml.gz';
$reader->open($src);
然后,compress.zlib包装器读取的内容将通过DarnFilter“路由”,DarnFilter必须找到可以插入xmlns:xsi声明的(第一个)位置。但这非常混乱,并且需要花一些时间来做正确的事(例如理论上,桶A可以包含xs
,桶B i:schem
和桶C aLocation="
)
更新2:这是一个特殊的php过滤器示例,它插入了xsi名称空间声明。大部分未经测试(使用我运行的一个测试;-))并且没有记录。把它作为概念验证而不是生产代码。
<?php
stream_filter_register('darn', 'DarnFilter');
$src = 'php://filter/read=darn/resource=compress.zlib://d:/test.xml.gz';
$r = new XMLReader;
$r->open($src);
while($r->read()) {
echo '.';
}
class DarnFilter extends php_user_filter {
protected $buffer='';
protected $status = PSFS_FEED_ME;
public function filter($in, $out, &$consumed, $closing)
{
while ( $bucket = stream_bucket_make_writeable($in) ) {
$consumed += $bucket->datalen;
if ( PSFS_PASS_ON == $this->status ) {
// we're already done, just copy the content
stream_bucket_append($out, $bucket);
}
else {
$this->buffer .= $bucket->data;
if ( $this->foo() ) {
// first element found
// send the current buffer
$bucket->data = $this->buffer;
$bucket->datalen = strlen($bucket->data);
stream_bucket_append($out, $bucket);
$this->buffer = null;
// no need for further processing
$this->status = PSFS_PASS_ON;
}
}
}
return $this->status;
}
/* looks for the first (root) element in $this->buffer
* if it doesn't contain a xsi namespace decl inserts it
*/
protected function foo() {
$rc = false;
if ( preg_match('!<([^?>\s]+)\s?([^>]*)>!', $this->buffer, $m, PREG_OFFSET_CAPTURE) ) {
$rc = true;
if ( false===strpos($m[2][0], 'xmlns:xsi') ) {
echo ' inserting xsi decl ';
$in = '<'.$m[1][0]
. ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
. $m[2][0] . '>';
$this->buffer = substr($this->buffer, 0, $m[0][1])
. $in
. substr($this->buffer, $m[0][1] + strlen($m[0][0]));
}
}
return $rc;
}
}
更新3:这是一个用C#编写的临时解决方案
XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
// prime the XMLReader with the xsi namespace
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
using ( XmlReader reader = XmlTextReader.Create(
new GZipStream(new FileStream(@"\test.xml.gz", FileMode.Open, FileAccess.Read), CompressionMode.Decompress),
new XmlReaderSettings(),
new XmlParserContext(null, nsmgr, null, XmlSpace.None)
)) {
while (reader.Read())
{
System.Console.Write('.');
}
}
答案 1 :(得分:1)
在将XML传递给file_get_contents
之前,您可以str_replace
和XMLReader
。
为xsi前缀插入所需的名称空间声明:
$reader = new XMLReader;
$reader->xml(str_replace(
'<ShowVehicleRemarketing',
'<ShowVehicleRemarketing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"',
file_get_contents('http://example.com/data.xml')));
另一种选择是删除schemaLocation
属性:
$reader->xml(str_replace(
'xsi:schemaLocation="http://www.starstandards.org/STAR /STAR/Rev4.2.4/BODs/Standalone/ShowVehicleRemarketing.xsd"',
'',
file_get_contents('http://example.com/data.xml')));
但是,如果文档中有更多前缀,则必须替换所有前缀。
答案 2 :(得分:1)
xsi
命名空间通常保留用于Schema Instance Namespace:
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
如果不是,则您的XML文件不符合XML + NS且无法解析。所以你应该在源文档中解决这个问题。
关于xsi的注释:它比一些可能的其他命名空间更重要,因为它将验证解析器指向XML架构的正确架构位置。
答案 3 :(得分:0)
修复写出格式错误的XML的内容,或者编写单独的工具以便稍后执行修复。 (它不必同时将其全部读入内存,必须 - 将数据流入/流出,也许一次读取和写入一行。)
通过这种方式,您的阅读代码无需担心尝试使用数据和同时修复它。