php - Get all leaf from complex XML with attributes -


i have kind of xml file

myxml.xml

<?xml version="1.0" encoding="utf-8"?> <products nb="2" type="new">     <product ean="12345677654321">         <sku>product1</sku>         <parameters>            <short_desc> short description of product1 </short_desc>            <price currency="usd">19.65</price>         </parameters>     </product>     <product ean="12345644654321">         <sku>product2</sku>         <parameters>            <long_desc> long description of product2 </long_desc>            <price currency="usd">19.65</price>            <vat>20</vat>         </parameters>     </product> </products> 

i array this

/products/@nb /products/@type /products/product/@ean /products/product/sku /products/product/parameters/short_desc /products/product/parameters/long_desc /products/product/parameters/price /products/product/parameters/price/@currency /products/product/parameters/vat 

i result code

getpath.xsl

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/xsl/transform">     <xsl:output omit-xml-declaration="yes" indent="yes"/>     <xsl:strip-space elements="*"/>      <xsl:variable name="vapos">'</xsl:variable>      <xsl:template match="*[@* or not(*)] ">       <xsl:if test="not(*)">          <xsl:apply-templates select="ancestor-or-self::*" mode="path"/>          <xsl:text>&#xa;</xsl:text>         </xsl:if>         <xsl:apply-templates select="@*|*"/>     </xsl:template>      <xsl:template match="*" mode="path">         <xsl:value-of select="concat('/',name())"/>         <xsl:variable name="vnumprecsiblings" select=          "count(preceding-sibling::*[name()=name(current())])"/>         <xsl:if test="$vnumprecsiblings">             <xsl:value-of select="concat('[', $vnumprecsiblings +1, ']')"/>         </xsl:if>     </xsl:template>      <xsl:template match="@*">         <xsl:apply-templates select="../ancestor-or-self::*" mode="path"/>         <xsl:value-of select="concat('/@',name())"/>         <xsl:text>&#xa;</xsl:text>     </xsl:template> </xsl:stylesheet>  $xsldoc = new \domdocument(); $xsldoc->substituteentities = true; $xsldoc->load('getpath.xsl');  $xmldoc = new \domdocument(); $xmldoc->load('myxml.xml');  $proc = new \xsltprocessor(); $proc->importstylesheet($xsldoc); $rest = $proc->transformtoxml($xmldoc);  $res = preg_replace("/\\s/"," ", $rest);  $path = explode(" ", $res);  foreach ($path $key => $value) {     if(!empty($value) && !preg_match("/\[.*\]/", $value))         $fields[] = $value; }  return $fields; 

this code give me

/products/@nb /products/@type /products/product/@ean /products/product/sku /products/product/parameters/short_desc /products/product/parameters/price /products/product/parameters/price/@currency 

/products/product/parameters/long_desc , /products/product/parameters/price/vat missing :(

how can parse full xml xslt ? or have solution without xslt ???

yeah can xpath in php.

$dom = new domdocument(); $dom->loadxml($xml); $xpath = new domxpath($dom);  function getnodeexpression(domnode $node, array &$namespaces) {   $name = $node->localname;   $namespace = $node->namespaceuri;   if ($namespace == '') {     return ($node instanceof domattr ? '@' : '').$name;   } elseif (isset($namespaces[$namespace])) {     $prefix = $namespaces[$namespace];   } else {     $xmlns = $prefix = ($node->prefix == '') ? 'ns' : $node->prefix;     $i = 1;     while (in_array($xmlns, $namespaces)) {       $xmlns = $prefix.'-'.$i;       $i++;     }     $namespaces[$namespace] = $prefix;   }   return ($node instanceof domattr ? '@' : '').$prefix.':'.$name; }  $result = []; $namespaces= []; foreach ($xpath->evaluate('//*[count(*) = 0]|//@*') $node) {   $path = '';   foreach ($xpath->evaluate('ancestor::*', $node) $parent) {     $path = '/'.getnodeexpression($parent, $namespaces);   }   $path .= '/'.getnodeexpression($node, $namespaces);   $result[$path] = true; } 

output: https://eval.in/118054

array(10) {   [0]=>   string(13) "/products/@nb"   [1]=>   string(15) "/products/@type"   [2]=>   string(13) "/product/@ean"   [3]=>   string(12) "/product/sku"   [4]=>   string(22) "/parameters/short_desc"   [5]=>   string(17) "/parameters/price"   [6]=>   string(16) "/price/@currency"   [7]=>   string(21) "/parameters/long_desc"   [8]=>   string(20) "/long_desc/@xml:lang"   [9]=>   string(15) "/parameters/vat" } array(1) {   ["http://www.w3.org/xml/1998/namespace"]=>   string(3) "xml" } 

the complex part @ resolve namespaces , generate prefixes them. let's take detailed look:

get local name (tag name without namespace prefix) , namespace.

$name = $node->localname; $namespace = $node->namespaceuri; 

if namespace empty not need prefix return expression node name.

  if ($namespace == '') {     return ($node instanceof domattr ? '@' : '').$name; 

otherwise check if namespace used on node , reuse prefix.

  } elseif (isset($namespaces[$namespace])) {     $prefix = $namespaces[$namespace]; 

if here unknown namespace, read prefix used on node. if node didn't use prefix use string "ns".

  } else {     $xmlns = $prefix = ($node->prefix == '') ? 'ns' : $node->prefix; 

validate prefix not used namespace add number , increase until have unique prefix.

    $i = 1;     while (in_array($xmlns, $namespaces)) {       $xmlns = $prefix.'-'.$i;       $i++;     } 

store namespace => prefix definition next call.

    $namespaces[$namespace] = $prefix; 

return expression including prefix.

  return ($node instanceof domattr ? '@' : '').$prefix.':'.$name; 

the namespace array can used register needed namespace prefix on xpath object.


Comments

Popular posts from this blog

visual studio - vb.net filter binding source by time -

php - SPIP: From Tag directly to an article -

jquery - isAjaxRequest always return false -