2016-11-15 43 views
0

這是我的問題。我想創建一個函數,它接受一個包含xpath的外部變量,並且一旦函數運行,我想添加到同一個變量中以創建一個計數器。向變量添加額外的字符串 - PHP

所以我有外面的變量:

$node = $xmlDoc->xpath('//a:Order'); 

然後,將採取外部變量($node)一個參數的函數。像這樣:

function loopXML($node) { 
    i=1; //counter variable 
} 

現在我想添加一個計數器到$ node,以便它通過所有的「訂單」的孩子。在功能之外,我會使用:

$child = $xmlDoc->xpath('//a:Order['.$i.']/*'); 

但是在函數內部,我不知道如何連接它。有沒有人有任何想法我可以做到這一點?

編輯: 此外,應該指出的是,我創建已經任意命名空間:

foreach($xmlDoc->getDocNamespaces() as $strPrefix => $strNamespace) { 
    if(strlen($strPrefix)==0) { 
     $strPrefix="a"; //Assign an arbitrary namespace prefix. 
    } 
    $xmlDoc->registerXPathNamespace($strPrefix,$strNamespace); 
} 
+0

爲什麼你將'$ node'傳遞給函數?它是如何使用的? – AbraCadaver

+0

該函數的目標是將xml轉換爲csv。 $ node是xml父xml標籤來循環。 $ child是$ node的所有子節點。我不得不這樣做很多,所以我想創建一個函數來減少冗餘,所以我可以只包含我想要的xpath(或xml標記)。 – Twigs

+0

另外,爲什麼不使用原始節點上的[$ xml-> children()](http://php.net/manual/en/simplexmlelement.children.php)屬性,以便可以迭代它們? –

回答

1

SimpleXMLElement::xpath()使用與SimpleXML的元素作爲上下文關聯的節點,所以你可以這樣做:

foreach ($xmlDoc->xpath('//a:Order') as $order) { 
    foreach ($order->xpath('*') as $field) { 
    ... 
    } 
} 

但SimpleXMLElement :: children()是元素子節點的列表,因此它返回的結果與Xpath表達式*相同,或者更確切地說是'*[namespace-uri == ""]'。第一個參數是你想要獲取的孩子的命名空間。

foreach ($xmlDoc->xpath('//a:Order') as $order) { 
    foreach ($order->children() as $field) { 
    ... 
    } 
} 

這可以很容易地重構成一個函數。

function getRecord(SimpleXMLelement $order, $namespace) { 
    $result = []; 
    foreach ($order->children($namespace) as $field) { 
    $result[$field->getName()] = (string)$field; 
    } 
    return $result; 
} 

你應該總是依賴實際的命名空間,而不是前綴。前綴可以更改並且是可選的。

放在一起:

$xml = <<<'XML' 
<a:orders xmlns:a="urn:a"> 
    <a:order> 
    <a:foo>bar</a:foo> 
    <a:answer>42</a:answer> 
    </a:order> 
</a:orders> 
XML; 

$namespace = 'urn:a'; 

$orders = new SimpleXMLElement($xml); 
$orders->registerXpathNamespace('a', $namespace); 

function getRecord(SimpleXMLelement $order, $namespace = NULL) { 
    $result = []; 
    foreach ($order->children($namespace) as $field) { 
    $result[$field->getName()] = (string)$field; 
    } 
    return $result; 
} 

foreach ($orders->xpath('//a:order') as $order) { 
    var_dump(getRecord($order, $namespace)); 
} 

輸出:

array(2) { 
    ["foo"]=> 
    string(3) "bar" 
    ["answer"]=> 
    string(2) "42" 
} 
+0

我試過這個,但似乎沒有得到它的工作。值得注意的是我已經創建了一個任意的命名空間。 – Twigs

+0

其中一個限制是如果在表達式中使用它們,則必須在每個調用'xpath()'的SimpleXMLElement上註冊名稱空間。 – ThW

0

所以我用了大量的谷歌搜索和THW的幫助了它。所有的幫助,謝謝。下面是我如何工作:

$orderPNode = '//a:Order'; 
$amazonRawXML = 'AmazonRaw.xml'; 
$amazonRawCSV = 'AmazonRaw.csv'; 


function loopXML($xmlDoc, $node, $writeCsv) { 
$i = 1; 
$xmlDocs = simplexml_load_file($xmlDoc); 
$result = []; 

foreach($xmlDocs->getDocNamespaces() as $strPrefix => $strNamespace) { 
    if(strlen($strPrefix)==0) { 
     $strPrefix="a"; //Assign an arbitrary namespace prefix. 
    } 
$xmlDocs->registerXPathNamespace($strPrefix,$strNamespace); 
} 

file_put_contents($writeCsv, ""); // Clear contents of csv file after each go 

$nodeP = $xmlDocs->xpath($node); 

foreach ($nodeP as $n) { 
    $nodeC = $xmlDocs->xpath($node.'['.$i.']/*'); 
    if($nodeC) { 
     foreach ($nodeC as $value) { 
      $values[] = $value; 
     } 
    $write = fopen($writeCsv, 'a'); 
    fputcsv($write, $values); 
    fclose($write); 

    $values = []; 
    $i++; 
    } else { 
     $result[] = $n; 
     $i++; 
    } 

} 
return $result; 
} 
loopXML($amazonRawXML, $orderPNode, $amazonRawCSV);