我正在獲取一些 xml 并將其轉換為類似于下面的 csv。一些記錄具有附加的 n(無界)元素(“EntityEvents”)。我怎樣才能獲取它們并將它們寫入第二個 (mm) csv 檔案?
這是我的結構:
XML 檔案:
<abc:ABCData xmlns:abc="http://www.abc-example.com" xmlns:xyz="http:/www.xyz-example.com">
<abc:ABCRecords>
<abc:ABCRecord>
<abc:ABC>5EXZX4LPK</abc:ABC>
<abc:Entity>
<abc:Name>Bornheim</abc:Name>
<abc:EntityEvents>
<abc:EntityEvent>
<abc:EntityEventType>TypeA</abc:EntityEventType>
<abc:EntityEventName>EventA</abc:EntityEventName>
</abc:EntityEvent>
</abc:EntityEvents>
</abc:Entity>
</abc:ABCRecord>
<abc:ABCRecord>
<abc:ABC>5967007LI</abc:ABC>
<abc:Entity>
<abc:Name>MOON BANK</abc:Name>
<abc:EntityEvents>
<abc:EntityEvent>
<abc:EntityEventType>TypeB</abc:EntityEventType>
<abc:EntityEventName>EventB</abc:EntityEventName>
</abc:EntityEvent>
<abc:EntityEvent>
<abc:EntityEventType>TypeC</abc:EntityEventType>
<abc:EntityEventName>EventC</abc:EntityEventName>
</abc:EntityEvent>
</abc:EntityEvents>
</abc:Entity>
</abc:ABCRecord>
<abc:ABCRecord>
<abc:ABC>2792340TZ</abc:ABC>
<abc:Entity>
<abc:Name>SUN BANK</abc:Name>
<abc:EntityEvents>
<abc:EntityEvent>
<abc:EntityEventType>TypeD</abc:EntityEventType>
<abc:EntityEventName>EventD</abc:EntityEventName>
</abc:EntityEvent>
<abc:EntityEvent>
<abc:EntityEventType>TypeF</abc:EntityEventType>
<abc:EntityEventName>EventF</abc:EntityEventName>
</abc:EntityEvent>
<abc:EntityEvent>
<abc:EntityEventType>TypeG</abc:EntityEventType>
<abc:EntityEventName>EventG</abc:EntityEventName>
</abc:EntityEvent>
</abc:EntityEvents>
</abc:Entity>
</abc:ABCRecord>
</abc:ABCRecords>
</abc:ABCData>
PHP 檔案:
<?php
$reader = new XMLReader();
$reader->open('php://stdin');
$output = fopen('php://stdout', 'w');
fputcsv($output, ['id', 'name']);
$xmlns = [
'abc' => 'http://www.abc-example.com'
];
$dom = new DOMDocument;
$xpath = new DOMXpath($dom);
foreach ($xmlns as $prefix => $namespaceURI) {
$xpath->registerNamespace($prefix, $namespaceURI);
}
while (
$reader->read() &&
(
$reader->localName !== 'ABCRecord' ||
$reader->namespaceURI !== $xmlns['abc']
)
) {
continue;
}
while ($reader->localName === 'ABCRecord') {
if ($reader->namespaceURI === 'http://www.abc-example.com') {
$node = $reader->expand($dom);
fputcsv(
$output,
[
$xpath->evaluate('string(abc:ABC)', $node),
$xpath->evaluate('string(abc:Entity/abc:Name)', $node)
]
);
}
$reader->next('ABCRecord');
}
輸出 1 (CSV):
5EXZX4LPK,Bornheim
5967007LI,"MOON BANK"
2792340TZ,"SUN BANK"
所需輸出 2 (CSV):
5EXZX4LPK,TypeA,EventA
5967007LI,TypeB,EventB
5967007LI,TypeC,EventC
2792340TZ,TypeD,EventD
2792340TZ,TypeE,EventE
2792340TZ,TypeF,EventF
我怎樣才能做到這一點?我想把它們寫到一個單獨的檔案中,但我不知道如何完成這個。我也愿意分兩步完成,這意味著在一個單獨的 php 檔案中。
uj5u.com熱心網友回復:
打開輔助檔案句柄。然后在將節點擴展為 DOM 后,使用運算式獲取事件并將它們寫入第二個檔案。
//...
$node = $reader->expand($dom);
// store the identifier
$identifier = $xpath->evaluate('string(abc:ABC)', $node);
fputcsv(
$output,
[
$identifier,
$xpath->evaluate('string(abc:Entity/abc:Name)', $node)
]
);
// iterate the EntityEvent elements
foreach ($xpath->evaluate('abc:Entity/abc:EntityEvents/abc:EntityEvent', $node) as $event) {
fputcsv(
$detailOutput,
[
$identifier,
$xpath->evaluate('string(abc:EntityEventType)', $event),
$xpath->evaluate('string(abc:EntityEventName)', $event)
]
);
}
//...
您問題中的代碼在 XMLReader 中實作了第一個節點串列迭代,以避免將整個檔案加載到記憶體中。在XMLReader::expand()你得到一個 DOM 節點之后。
使用 Xpath 讀取 DOM 始終是兩者之一。基本位置路徑回傳一個節點串列(例如:ancestor/parent/child)。結果將始終是一個串列,如果運算式不匹配,它將是一個空串列。Xpath 運算式可以變得更加復雜——它們允許條件、嵌套和替代。
如果您需要單個值,您可以使用 Xpath 函式轉換位置路徑(例如:)string(ancestor/parent/child)。類似string()or的函式number()將從節點串列中轉換第一個值或回傳默認值。string()如果運算式本身不匹配,將回傳一個空字串。其他方法或運算子的使用也可能導致型別轉換(例如:)count(ancestor/parent/child) > 0。
但是,如果您可以使用 DOM 方法/屬性從當前節點讀取值,我建議您這樣做。在這種情況下,Xpath 是不必要的開銷。
// fetch and iterate nodes
foreach ($xpath->evaluate($expression, $contextNode) as $childNode) {
var_dump(
// reading an attribute
$childNode->getAttribute('attribute-one'),
// the node name (without the namespace prefix)
$childNode->localName,
// using Xpath for nested data
$xpath->evaluate('string(child)', $childNode)
);
}
uj5u.com熱心網友回復:
我會做一些不同的事情:
$targets = $xpath->query("//abc:ABCRecord");
foreach ($targets as $target) {
$id = $xpath->query('.//abc:ABC', $target)[0]->nodeValue;
$events = $xpath->query('.//abc:EntityEvent', $target);
foreach ($events as $event) {
$type = $xpath->query('.//abc:EntityEventType', $event)[0]->nodeValue;
$name = $xpath->query('.//abc:EntityEventName', $event)[0]->nodeValue;
fputcsv(
$output,
[
$id,
$type,
$name
]
);
}
}
uj5u.com熱心網友回復:
使用單個 XPath 運算式和標記名稱來填充陣列。構建一個 csv 物件應該是微不足道的。
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$csv1 = [];
$csv2 = [];
foreach ($xpath->evaluate("(//abc:ABCRecord/abc:ABC | //abc:Entity/abc:Name) | (//abc:ABCRecord/abc:ABC | //abc:ABCRecord//abc:EntityEvent)") as $ele) {
if($ele -> localName == 'ABC'){
$n = $ele->nodeValue;
}
if($ele -> localName == 'Name'){
$csv1[] = $n . ','. $ele -> nodeValue;
}else if($ele -> localName == 'EntityEvent'){
$csv2[] = $n . ','. $ele -> nodeValue;
}
}
var_dump($csv1);
var_dump($csv2);
結果
array(3) {
[0]=>
string(18) "5EXZX4LPK,Bornheim"
[1]=>
string(19) "5967007LI,MOON BANK"
[2]=>
string(18) "2792340TZ,SUN BANK"
}
array(6) {
[0]=>
string(16) "5EXZX4LPK,EventA"
[1]=>
string(16) "5967007LI,EventB"
[2]=>
string(16) "5967007LI,EventC"
[3]=>
string(16) "2792340TZ,EventD"
[4]=>
string(16) "2792340TZ,EventF"
[5]=>
string(16) "2792340TZ,EventG"
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/464286.html
上一篇:需要從多個元素中選擇唯一的一個值
