I have that 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 the product1 </short_desc>
<price currency="USD">19.65</price>
</parameters>
</product>
<product ean="12345644654321">
<sku>Product2</sku>
<parameters>
<long_desc> Long description of the product2 </long_desc>
<price currency="USD">19.65</price>
<vat>20</vat>
</parameters>
</product>
</products>
I would an array like 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 almost this result with this 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>
</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>
</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 as $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 and /products/product/parameters/price/vat are missing :(
How can I parse the full XML with xslt ? Or have you a solution without XSLT ???
Yeah you can do it with some Xpath in PHP.
Output: https://eval.in/118054
The complex part at this is to resolve the namespaces and generate prefixes for them. So let's take a detailed look:
Get the local name (tag name without namespace prefix) and the namespace.
If the namespace is empty we do not need any prefix return an expression with just the node name.
Otherwise check if the namespace was already used on another node and reuse that prefix.
If here is an unknown namespace, read the prefix used on this node. If the node didn't use a prefix use the string "ns".
Validate that the prefix is not already used for another namespace add a number and increase it until we have an unique prefix.
Store the namespace => prefix definition for the next call.
Return an expression including the prefix.
The namespace array can be used to register all needed namespace prefix on an Xpath object.