1. Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.

Steam API XML parse into css?

Discussion in 'Programming & Webmastering' started by Solaris17, Aug 25, 2014.

  1. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    Hi guys more of a proof of concept im curious about I was looking at hosting a csgo server (irrelevant fun project) which got put on hold when I got interested in the API server status you can run which is this

    api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=71.180.229.246&format=xml

    The issue is this pulls raw xml with no CSS styling and I was simply wondering if it was possible to make a php file that could call that link maybe and parse it into preset css?

    This is more proof of concept than anything but im curious how you could parse the xml tags and style them so that if it were embeded into a website it would be presentable data.

    the server IP is my own
     
  2. Jizzler

    Jizzler

    Joined:
    Aug 10, 2007
    Messages:
    3,464 (1.29/day)
    Thanks Received:
    650
    Location:
    Geneva, FL, USA
    I see that the API also has a JSON output option.
    PHP:
    $url 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=71.180.229.246';

    $server json_decode(file_get_contents($url), true)['response']['servers'][0];

    print_r($server);

    /* (
        [addr] => 71.180.229.246:27015
        [gmsindex] => 65534
        [appid] => 730
        [gamedir] => csgo
        [region] => -1
        [secure] => 1
        [lan] =>
        [gameport] => 27015
        [specport] => 0
    ) */
    Not that XML would have been a problem.
    PHP:
    $url 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=71.180.229.246&format=xml';

    $xml simplexml_load_string(file_get_contents($url));

    echo 
    $xml->servers->server->addr;
    //etc...
    It could get certainly get more elaborate than that. An AJAX call after the page is loaded could prevent hang-ups if Steam is down or slow.

    -edit-

    I shouldn't go straight for the ['servers'][0] since I realized now that the server may not be up and the response should be checked first :) (it's late, could help ya more tomorrow)
     
    Last edited: Aug 25, 2014
    Solaris17 says thanks.
  3. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    JSON is probably the better way to go simply because it will use less bandwidth.

    No matter which you use, make sure to check ['response']['success'] == true before attempting to access the ['servers'] set. Servers is a list so enumerate through it looking for ['gamedir'] == "csgo"

    You'll want to echo the data into HTML with the necessary class and id tags for CSS to work off of.
     
    Solaris17 says thanks.
    Crunching for Team TPU
  4. Aquinus

    Aquinus Resident Wat-man

    Joined:
    Jan 28, 2012
    Messages:
    6,867 (6.48/day)
    Thanks Received:
    2,469
    Location:
    Concord, NH
    Theoretically, a library like Enlive for Clojure could transform the XML into an appropriate HTML document, but honestly you should just process the response of the API call and not transform (in the sense of transformations) it into something pretty looking. The prettiness (HTML sent to an end user) and the XML response (coming into the server from Steam's API) are two very different things, try to keep them that way. It would be more wise to have an HTML template that uses the data from said response.

    Note: If you wrote an API to turn it into JSON, you could do most of it client side in a language like JavaScript or a derivative.
     
    Solaris17 says thanks.
  5. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    Just remove the &format=xml and it returns JSON.
     
    Solaris17 and Aquinus say thanks.
    Crunching for Team TPU
  6. Aquinus

    Aquinus Resident Wat-man

    Joined:
    Jan 28, 2012
    Messages:
    6,867 (6.48/day)
    Thanks Received:
    2,469
    Location:
    Concord, NH
    Quick way of saying you don't need a sliver of server-side code to handle this. You can do this with JS and HTML alone.
     
  7. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    if you didnt want to start with servers[0] what would you start with? Can you modify the json output as separate objects like you can with XML I'm not familiar with it but it appears you can but this way it just displays the full array string from $url correct?

    infact looking at it it seems to me like it would be logical to break the json up via

    Code:
    $server = json_decode(file_get_contents($url), true)['response']['servers'][0];
    into something like

    Code:
    $server = json_decode(file_get_contents($url), true)['response']['addr'][0];
    going by these catagories

    Code:
    <response>
    <success>true</success>
    <servers>
    <server>
    <addr>71.180.229.246:27015</addr>
    <gmsindex>65534</gmsindex>
    <appid>730</appid>
    <gamedir>csgo</gamedir>
    <region>-1</region>
    <secure>true</secure>
    <lan>false</lan>
    <gameport>27015</gameport>
    <specport>0</specport>
    </server>
    </servers>
    </response>
    
    but using addr does not seem to work. does it not because it is nested inside of 'server'?
     
    Last edited: Aug 26, 2014
  8. Aquinus

    Aquinus Resident Wat-man

    Joined:
    Jan 28, 2012
    Messages:
    6,867 (6.48/day)
    Thanks Received:
    2,469
    Location:
    Concord, NH
    Both XML and JSON represent the data the same. You would still need to take the first <server> tag from <servers>. The code for XML there is misleading because you still need to do something similar with the XML. I should also add that JSON parsers for many languages tend to be vastly faster than XML parsers.

    Is there a particular way you want this done or do you have something specific in mind? I ask this because HTML/JS is the best way to eliminate the middleman (server) for checking status and requires zero server-side code which would make the page incredibly responsive and lean on bandwidth for the server. JSON can make this incredibly easy and efficient.
     
    Solaris17 says thanks.
  9. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    I simply wanted to parse the data I received via the API into easy to read brackets like

    Online:

    Server:

    Port:

    Secure:

    So that I could embed it in a webpage that was my whole purpose I just couldn't figure out how to make it "Pretty" The data is functional but it isnt what a normal user would want to see and seeing as I know close to nothing with pulling this data and making it readable I wanted to learn on the way I am at anyone's mercy when it comes to this. The best I can provide is common sense and a logical thought process.
     
  10. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    Tweaking Jizzler's code...
    PHP:
    $ip 'SNIP';
    $appid 730// Counter-Strike: Global Offensive

    $url 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=' $ip;

    $response json_decode(file_get_contents($url), true)['response'];

    if (
    $response['success']) // Make sure Valve was able to query the server.
    {
      echo 
    $ip " Online<br/>Servers:<ul>";
      for (
    $i=0$i count($response['servers']); $i++) // Check each server in the response.
      
    {
        if (
    $response['servers'][$i]['appid'] == $appid// Make sure the host matches requested.
        
    {
          echo 
    "<li>" explode(':'$response['servers'][$i]['addr'])[1]; // Get the port number.
          
    if ($response['servers'][$i]['secure'])
          {
            echo 
    " Secured";
          }
         echo 
    "</li>";
        }
      }
      echo 
    "</ul>";
    }
    else
    {
      echo 
    $ip " Offline"// Nothing to see here; move along.
    }
    Code is untested. Edit the echo lines to make it pretty. Put a DIV or SPAN around it, put it in table, whatever.

    It should look like:
    In theory, anyway. If you had two more CSGO servers running on the same IP, one was secured and one wasn't, it should look like this:
     
    Last edited: Aug 26, 2014
    Solaris17 says thanks.
    Crunching for Team TPU
  11. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    Thanks ford :toast: I do have an issue with this version when calling the IP it appears to break it I get the 71.18 echos to the page but nothing else so I imagine its a problem with the first 2 lines?

    Code:
    $ip = '71.180.229.246';
    $url = 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=' + $ip;
    
    but I am unsure if it is a context issue or further down?

    nevermind I broke it with a line break that stopped the ?> at the end of the document.
     
  12. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    I made a lot of changes. I was using the wrong character (+) to concatenate strings. I haven't wrote PHP in forever.
     
    Solaris17 says thanks.
    Crunching for Team TPU
  13. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    So basically for JSON in general php has a built in decode flag and you simply make each section a variable?
     
  14. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    json_decode processes the entire file into a mixed array. Do:
    PHP:
    print_r(json_decode(file_get_contents($url), true));
    To see the whole array. We're just jumping to the parts we care about.

    simplexml_load_string loads it into a class describing the entire XML so you have to step through the children using -> . Arrays are easy to work with because you can copy part of it and focus on it easily.
     
    Solaris17 says thanks.
    Crunching for Team TPU
  15. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    So was that why Jizzlers example included
    Code:
    echo $xml->servers->server->addr;
    ? Am I correct in reading it linear? you MUST do servers->server and not just 'server'?
     
  16. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    Yes, because look at the hierarchy of the XML:
    Code:
    <response>
    	<success>true</success>
    	<servers>
    		<server>
    			<addr>SNIP:27015</addr>
    			<gmsindex>65534</gmsindex>
    			<appid>730</appid>
    			<gamedir>csgo</gamedir>
    			<region>-1</region>
    			<secure>true</secure>
    			<lan>false</lan>
    			<gameport>27015</gameport>
    			<specport>0</specport>
    		</server>
    	</servers>
    </response>
    The reason why you can ignore response is because the root element is implicit and required. $xml effectively refers to response because it always refers to the root element which is response in this case. You can access success via $xml->success.

    There can be more than one server in servers. I suspect Jizzler's XML code would break (or only reach #0) if that were the case).
     
    Last edited: Aug 26, 2014
    Solaris17 says thanks.
    Crunching for Team TPU
  17. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    I really appreciate the explanation thank you. For those that want to know I did modify the code a bit to make it a little more precise. For example if something is running on the IP valve will still query success and thus the CS server will read as online. However if you query the port it will switch to offline the second the server goes down..or rather when valves API catches up to see if its down.

    Code:
    $ip = '71.180.229.246';
    $appid = 730; // Counter-Strike: Global Offensive
    
    $url = 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=' . $ip;
    
    $response = json_decode(file_get_contents($url), true)['gameport'];
    
    if ($response['your-port-here']) // Make sure Valve was able to query the server.
    {
      echo $ip . " Online<br/>Servers:<ul>";
      for ($i=0; $i < count($response['servers']); $i++) // Check each server in the response.
      {
        if ($response['servers'][$i]['appid'] == $appid) // Make sure the host matches requested.
        {
          echo "<li>" . explode(':', $response['servers'][$i]['addr'])[1]; // Get the port number.
          if ($response['servers'][$i]['secure'])
          {
            echo " Secured";
          }
         echo "</li>";
        }
      }
      echo "</ul>";
    }
    else
    {
      echo $ip . " Offline"; // Nothing to see here; move along.
    }
    EDIT:: nvm this did not work.
     
    Last edited: Aug 26, 2014
  18. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    Success is based on whether or not api.steampowered.com could invoke a response from 71.180.229.246 at all. That's why it can be successful but not have any servers available. If I were you, I wouldn't show anything on success and "71.180.229.246 unreachable" on fail. The mere presence of an instance under servers says that specific server is online. If it is offline, it simply won't be in the list. If you want to simulate your typical offline/online message, you have to check for the specific instance of a server. If exists, online; if doesn't exist, offline.

    I would probably use the gameport field for that. Also using gameport, you could get rid of the explode bit (silly me).
     
    Solaris17 says thanks.
    Crunching for Team TPU
  19. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    Thats what I was looking into. More for education the steam API for example will show success when it can query the IP itself however it will not generate some subsets in this example gameport is not created if the game is not found but the IP is reachable. In my case I attempted to modify it to ask for the gameport group and fail or ask for gameports response IE the port number or fail since this would be even more accurate because even if the IP is infact unreachable gameport would not be polled and the response would still be fail.

    at least that was my logic behind it.
     
  20. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    I'm pretty sure api.steampowered.com is accessing Steam on the computer hosting. Success is based on whether or not the API was able to connect. If it can't connect, there will be no instances of server under servers.

    In your example above, I believe it would always fail because $response will never contain your port number, always success and servers.
     
    Crunching for Team TPU
  21. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
  22. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    I did manage to make the correct adjustment it seems like this time I used the variable "servers" since the steam API does not create the opening <servers> and only the closing </servers> if you poll "servers" it does not require much modification

    Code:
    $ip = 'your-IP';
    $appid = 730; // Counter-Strike: Global Offensive
    
    $url = 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=' . $ip;
    
    $response = json_decode(file_get_contents($url), true)['reponse'];
    
    if ($response['servers']) // Make sure Valve was able to query the server.
    {
      echo $ip . " Online<br/>Servers:<ul>";
      for ($i=0; $i < count($response['servers']); $i++) // Check each server in the response.
      {
        if ($response['servers'][$i]['appid'] == $appid) // Make sure the host matches requested.
        {
          echo "<li>" . explode(':', $response['servers'][$i]['addr'])[1]; // Get the port number.
          if ($response['servers'][$i]['secure'])
          {
            echo " Secured";
          }
         echo "</li>";
        }
      }
      echo "</ul>";
    }
    else
    {
      echo $ip . " Offline"; // Nothing to see here; move along.
    }
     
  23. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    Here's what I came up with:
    PHP:
    $ip 'SNIP';
    $servers = array(
            array(
    27015730// port 27015 should have Counter-Strike: Global Offensive
        
    );
    /* Example of many servers:

    $servers = array(
            array(27015, 730), // port 27015 should have Counter-Strike: Global Offensive
            array(7777, 104900), // port 7777 should have ORION: Prelude
            array(26015, 91700) // port 26015 should have E.Y.E: Divine Cybermancy
        );

    */

    $url 'http://api.steampowered.com/ISteamApps/GetServersAtAddress/v0001?addr=' $ip;

    $response json_decode(file_get_contents($url), true)['response'];

    function 
    IndexOfServer($serverarray$portappid// Finds the gameport + appid in the response and returns the index.
    {
        for (
    $i=0$i count($serverarray); $i++) // Check each server in the response.  If there are no servers, it will fall through to return -1.
        
    {
            if ((
    $serverarray[$i]['gameport'] == $portappid[0]) && ($serverarray[$i]['appid'] == $portappid[1]))
            {
                return 
    $i// I found it!
            
    }
        }
        return -
    1// I couldn't find it.
    }

    if (
    $response['success']) // Make sure Valve was able to query the server.
    {
        echo 
    '<ul>'// Start unordered list
        
    for ($s=0$s count($servers); $s++) // Loop through our list of expected servers.
        
    {
            
    $i IndexOfServer($response['servers'], $servers[$s]);
            
    $secured ''// Placeholder for our secured message, if it is secured.
            
    echo '<li class="';
            if (
    $i == -1)
            {
                echo 
    'offline'// This server that was expected to be found was not so we must assume it is offline.
            
    }
            else
            {
                echo 
    'online';
                if (
    $response['servers'][$i]['secure'])
                {
                    
    $secured ' Secured'// Would recommend replacing this with an <img /> of a padlock.
                
    }
            }
            echo 
    '">' $servers[$s][0] . $secured '</li>';
        }
        echo 
    "</ul>"// End unordered list
    }
    else
    {
      echo 
    $ip ' unreachable'// Nothing to see here; move along.
    Use the offline and online classes to decorate the text to show status. For example, make offline red and online green.
     
    Last edited: Aug 26, 2014
    Solaris17 says thanks.
    Crunching for Team TPU
  24. Solaris17

    Solaris17 Creator Solaris Utility DVD

    Joined:
    Aug 16, 2005
    Messages:
    17,417 (5.10/day)
    Thanks Received:
    3,716
    Location:
    Florida
    This one only echos the server port in <li> form

    edit:

    Code:
     echo '<li class="';
            if ($i == -1)
    ? no closing > detected on notepad++?
     
  25. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    14,110 (6.24/day)
    Thanks Received:
    3,929
    Location:
    IA, USA
    Can you copy and paste the source it dumped?
     
    Crunching for Team TPU

Currently Active Users Viewing This Thread: 1 (0 members and 1 guest)

Share This Page