TecBrat
TecBrat

Reputation: 3719

exclude nodes from xpath query

Here's some code I am currently using. Where I need help are $bn_name_search and $bn_id_search

$xpath_base='/ItemSearchResponse/Items/Item[';
for ($i = 1; $i<=10; $i++)
  {
    $curr_item_base=$xpath_base.$i.']';
    $bn_name_search=$curr_item_base.'/BrowseNodes//BrowseNode/Name/text()';
    $bn_id_search=$curr_item_base.'/BrowseNodes//BrowseNode/BrowseNodeId/text()';
    $bn_names=$parsed->xpath($bn_name_search);
    $bn_ids=$parsed->xpath($bn_id_search);
  }

This gives me all the browsnode names and all the broswnode ids. What I'd like to do now is find only the browsenode names "BrowseNode/Name/" that are not "All Products" and only browsnode ids "BrowseNode/BrowseNodeId/" share a "BrowseNode/" with a name that is not "All Products" I don't have to test for the existance of BrowseNode/Name. It won't be blank if there is an ID. If I can put two negative expressions it would be even better. I would omit those whose names are "All Products" and those whose names are "Departments"

EDIT: Here's a block of the XML: Where it says "&lt;Name&gt;Departments&lt;/Name&gt;", I'd like to exclude that name and it's ID. If I have a similare one that says "&lt;Name&gt;All Products&lt;/Name&gt;" I'd also like to exclude that name and it's ID. (by ID, I mean &lt;BrowseNodeId&gt;)

<BrowseNodes>
  <BrowseNode>
    <BrowseNodeId>2346727011</BrowseNodeId>
    <Name>Casual</Name>
    <Ancestors>
      <BrowseNode>
        <BrowseNodeId>1045024</BrowseNodeId>
        <Name>Dresses</Name>
        <Ancestors>
          <BrowseNode>
            <BrowseNodeId>1040660</BrowseNodeId>
            <Name>Women</Name>
            <Ancestors>
              <BrowseNode>
                <BrowseNodeId>1036682</BrowseNodeId>
                <Name>Departments</Name>
                <IsCategoryRoot>1</IsCategoryRoot>
                <Ancestors>
                  <BrowseNode>
                    <BrowseNodeId>1036592</BrowseNodeId>
                    <Name>Clothing &amp; Accessories</Name>
                  </BrowseNode>
                </Ancestors>
              </BrowseNode>
            </Ancestors>
          </BrowseNode>
        </Ancestors>
      </BrowseNode>
    </Ancestors>
  </BrowseNode>
</BrowseNodes>

Upvotes: 4

Views: 1525

Answers (3)

JWiley
JWiley

Reputation: 3209

Without seeing how your xml is structured, I came up with xpath for what I thought you were trying to do. I also wasn't too sure about the BrowseNodeId that "share" a browsenode name, I assumed this meant to give the BrowseNodeIds for all BrowseNodes that had the name set to this.

I combined your xpath outside of the php to visualize it better:

/ItemSearchResponse/Items/Item[i]/BrowseNodes//BrowseNode/Name/text()
/ItemSearchResponse/Items/Item[i]/BrowseNodes//BrowseNode/

Combined solution:

/ItemSearchResponse/Items/Item[i]/BrowseNodes//BrowseNode/Name[text()!='All Products']/text()
/ItemSearchResponse/Items/Item[i]/BrowseNodes//BrowseNode[Name/text()!='All Departments']/BrowseNodeId/text()

Php solution:

$xpath_base='/ItemSearchResponse/Items/Item[';
for ($i = 1; $i<=10; $i++)
  {
    $curr_item_base=$xpath_base.$i.']';
    $bn_name_search=$curr_item_base.'/BrowseNodes//BrowseNode/Name[text()!='All Products']';
    $bn_id_search=$curr_item_base.'/BrowseNodes//BrowseNode[Name/text()!='All Departments']/BrowseNodeId/text()';
    $bn_names=$parsed->xpath($bn_name_search);
    $bn_ids=$parsed->xpath($bn_id_search);
  }

Updated To combine the xpath, you could use concatenate | :

/ItemSearchResponse/Items/Item[i]/BrowseNodes//BrowseNode[Name/text()!=\'Departments\' and Name/text()!=\'All Products\']/BrowseNodeId/text() | 
/ItemSearchResponse/Items/Item[i]/BrowseNodes//BrowseNode/Name[text()!=\'All Products\' and text()!=\'Departments\']

php: (Updated)

$bn_combined_search=$curr_item_base.'/BrowseNodes//BrowseNode[Name/text()!=\'Departments\' and Name/text()!=\'All Products\']/BrowseNodeId/text() |'.$curr_item_base.'/BrowseNodes//BrowseNode/Name[text()!=\'All Products\' and text()!=\'Departments\']';

If I made a wrong assumption, post some of your xml and elaborate on the solution you're looking for. Hope this helps!

Upvotes: 2

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

Use:

//BrowseNode
      [not(contains('|Departments|All Products|',
                    concat('|', Name, '|')
                    )
          )
      ]/Name

This expression selects any Name elements that is a child of a BrowseNode element and whose string value isn't one of the strings "Departments" or "All Products".

Use:

//BrowseNode
      [not(contains('|Departments|All Products|',
                    concat('|', Name, '|')
                    )
          )
      ]
       /BrowseNodeId

This selects any BrowseNodeId element that is a child of a BrowseNode element and that has a Name sibling whose string value isn't one of the strings "Departments" or "All Products".

XSLT - based verification:

<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:template match="/">
  <xsl:copy-of select=
   "//BrowseNode
      [not(contains('|Departments|All Products|',
                    concat('|', Name, '|')
                    )
          )
      ]/Name
      "/>
=================

  <xsl:copy-of select=
   "//BrowseNode
      [not(contains('|Departments|All Products|',
                    concat('|', Name, '|')
                    )
          )
      ]
       /BrowseNodeId
      "/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<BrowseNodes>
    <BrowseNode>
        <BrowseNodeId>2346727011</BrowseNodeId>
        <Name>Casual</Name>
        <Ancestors>
            <BrowseNode>
                <BrowseNodeId>1045024</BrowseNodeId>
                <Name>Dresses</Name>
                <Ancestors>
                    <BrowseNode>
                        <BrowseNodeId>1040660</BrowseNodeId>
                        <Name>Women</Name>
                        <Ancestors>
                            <BrowseNode>
                                <BrowseNodeId>1036682</BrowseNodeId>
                                <Name>Departments</Name>
                                <IsCategoryRoot>1</IsCategoryRoot>
                                <Ancestors>
                                    <BrowseNode>
                                        <BrowseNodeId>1036592</BrowseNodeId>
                                        <Name>Clothing &amp; Accessories</Name>
                                    </BrowseNode>
                                </Ancestors>
                            </BrowseNode>
                        </Ancestors>
                    </BrowseNode>
                </Ancestors>
            </BrowseNode>
        </Ancestors>
    </BrowseNode>
</BrowseNodes>

the two XPath expressions are evaluated and their results (separated by the "========" string are copied to the output.

We can thus verify from the result of the transformation that exactly the wanted Name and BrowseNodeId elements are selected:

<Name>Casual</Name>
<Name>Dresses</Name>
<Name>Women</Name>
<Name>Clothing &amp; Accessories</Name>
=================

<BrowseNodeId>2346727011</BrowseNodeId>
<BrowseNodeId>1045024</BrowseNodeId>
<BrowseNodeId>1040660</BrowseNodeId>
<BrowseNodeId>1036592</BrowseNodeId>

Upvotes: 2

Tom Imrei
Tom Imrei

Reputation: 1544

There you go:

$nodes = $parsed->xpath("//BrowseNode[Name!='Departments' and Name!='All Products']");
foreach ($nodes as $node) {
    echo "Id: {$node->BrowseNodeId}, name: {$node->Name}\n";
}

Upvotes: 2

Related Questions