Asked  7 Months ago    Answers:  5   Viewed   37 times

This is starting to piss me off real bad. I have this XML code:

Updated with correct namespaces

<?xml version="1.0" encoding="utf-8"?>

<Infringement xsi:schemaLocation="http://www.movielabs.com/ACNS http://www.movielabs.com/ACNS/ACNS2v1.xsd" xmlns="http://www.movielabs.com/ACNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Case>
    <ID>...</ID>
    <Status>Open</Status>
  </Case>
  <Complainant>
    <Entity>...</Entity>
    <Contact>...</Contact>
    <Address>...</Address>
    <Phone>...</Phone>
    <Email>...</Email>
  </Complainant>
  <Service_Provider>
    <Entity>...</Entity>
    <Address></Address>
    <Email>...</Email>
  </Service_Provider>
  <Source>
    <TimeStamp>...</TimeStamp>
    <IP_Address>...</IP_Address>
    <Port>...</Port>
    <DNS_Name></DNS_Name>
    <Type>...</Type>
    <UserName></UserName>
    <Number_Files>1</Number_Files>
    <Deja_Vu>No</Deja_Vu>
  </Source>
  <Content>
    <Item>
      <TimeStamp>...</TimeStamp>
      <Title>...</Title>
      <FileName>...</FileName>
      <FileSize>...</FileSize>
      <URL></URL>
    </Item>
  </Content>
</Infringement>

And this PHP code:

<?php 
    $data = urldecode($_POST["xml"]);
    $newXML = simplexml_load_string($data);

    var_dump($newXML->xpath("//ID"));
?>

I've dumped only $newXML and gotten tons of data, but the only xPath I've run that returned anything but an empty array was "*"

Isn't "//ID" supposed to find all ID nodes in the document? Why isn't it working?

Thanks

 Answers

53

I've dumped only $newXML and gotten tons of data, but the only xPath I've run that returned anything but an empty array was "*"

So what was returned from var_dump($newXML->xpath("*"));? <Infringement>?

If the problem is namespaces, try this:

var_dump($newXML->xpath("//*[local-name() = 'ID']"));

This will match any element in the document whose name is 'ID', regardless of namespace.

My stuff works if i replace all "xmlns" with "ns"

Wait, what? Are you sure you showed us all the xmlns-related attributes in the document?

Update: The question was edited to show that the XML really does have a default namespace declaration. That explains the original problem: your XPath expression selects ID elements that are in no namespace, but the elements in your document are in the movielabs ACNS namespace, thanks to the default namespace declaration.

The declaration xmlns="http://www.movielabs.com/ACNS" on an element means "this element and all descendants that don't have a namespace prefix (like ID) are in the namespace represented by the namespace URI 'http://www.movielabs.com/ACNS'." (Unless an intervening descendant has a different default namespace declaration, which would shadow this one.)

So use my local-name() answer above to ignore namespaces, or use jasso's technique to specify the movielabs ACNS and use it as intended.

Wednesday, March 31, 2021
 
devo
answered 7 Months ago
31

this might help

$obj = new SimpleXMLElement($xml);
$rtn = array();
$cnt = 0;
foreach($obj->xpath('///OSes/*/*') as $rec)
{
  foreach ($rec as $rec_obj)
  {
    if (!isset($rtn[$cnt]))
    {
      $rtn[$cnt] = array();
    }

    foreach ($rec_obj as $name=>$val)
    {
      $rtn[$cnt][(string)$name] = (string)$val;
    }
    ++$cnt;
  }
}
Saturday, May 29, 2021
 
dimitarvp
answered 5 Months ago
17

You were probably not "cycling" the countries and cities:

<?php
    $xml_file = '/path';
    $xml = simplexml_load_file($xml_file);

    foreach($xml->Continent as $continent) {
        echo "<div class='continent'>".$continent['Name']."<span class='status'>".$continent['Status']."</span>";
        foreach($continent->Country as $country) {
            echo "<div class='country'>".$country['Name']."<span class='status'>".$country['Status']."</span>";
            foreach($country->City as $city) {
                echo "<div class='city'>".$city['Name']."<span class='status'>".$city['Status']."</span></div>";
            }
            echo "</div>"; // close Country div
        }
        echo "</div>"; // close Continent div
    }
?>
Saturday, May 29, 2021
 
avon_verma
answered 5 Months ago
93

Use:

//page[@id=$yourId]/node()[not(self::page)]

This selects all nodes that are not page and that are children of any page in the document, the string value of whose id attribute is equal to the string contained in $yourId (most probably you would substitute $yourId above with a specific, desired string, such as '1').

Here is a simple 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:param name="pId" select="3"/>

 <xsl:template match="/">
     <xsl:copy-of select="//page[@id=$pId]/node()[not(self::page)]"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document (wrapped in a single top node to make it well-formed):

<pages>
    <page id='1'>
        <title>Page 1</title>
        <page id='2'>
            <title>Sub Page 1</title>
        </page>
        <page id='3'>
            <title>Sub Page 2</title>
        </page>
    </page>
    <page id='4'>
        <title>Page 2</title>
    </page>
</pages>

the wanted, correct result is produced:

<title>Sub Page 2</title>

Do note: One assumption made is that an id value uniquely identifies a page. If this is not so, the proposed XPath expression will select all page elements whose id attribute has a string valu of $yourId.

If this is the case and only one page element must be selected, the OP must specify which one of the many page elements with this id should be selected.

For example, it may be the first:

(//page[@id=$yourId]/node()[not(self::page)])[1]

or the last:

(//page[@id=$yourId]/node()[not(self::page)])[last()]

or ...

Tuesday, August 3, 2021
 
Tak
answered 3 Months ago
Tak
57

Your document has a default namespace, which means in the XPath model all the elements are in that namespace.

The query should be //html:head. You will have to supply the namespace mapping to the XPath query.

Note that while the XPath expression uses a namespace prefix, it is the namespace uri that must match.

XPathContext ctx = new XPathContext("html", "http://www.w3.org/1999/xhtml");
Nodes nodes = root.query("//html:head", ctx );
Tuesday, October 19, 2021
 
Bere
answered 4 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :