Search code examples
xmllinuxxpathxmlstarlet

How to extract specific strings from a XML file that share the same tag as other strings?


In the following XML snippet...

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" href="/static/atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:s="http://dev.splunk.com/ns/rest" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/">
  <title>serverclients</title>
  <id>https://splfwdprw2:8089/servicesNS/nobody/search/deployment/server/clients</id>
  <updated>2017-04-04T16:14:04-04:00</updated>
  <generator build="f3e41e4b37b2" version="6.3.1"/>
  <author>
    <name>Splunk</name>
  </author>
  <link href="/servicesNS/nobody/search/deployment/server/clients/_acl" rel="_acl"/>
  <link href="/servicesNS/nobody/search/deployment/server/clients/countClients_by_machineType" rel="countClients_by_machineType"/>
  <link href="/servicesNS/nobody/search/deployment/server/clients/countRecentDownloads" rel="countRecentDownloads"/>
  <link href="/servicesNS/nobody/search/deployment/server/clients/getMatchingAppsForClient_dryRun" rel="getMatchingAppsForClient_dryRun"/>
  <link href="/servicesNS/nobody/search/deployment/server/clients/preview" rel="preview"/>
  <opensearch:totalResults>1</opensearch:totalResults>
  <opensearch:itemsPerPage>18446744073709551615</opensearch:itemsPerPage>
  <opensearch:startIndex>0</opensearch:startIndex>
  <s:messages/>
  <entry>
    <title>00031e8f6c883544b8079037c5eba9ec</title>
    <id>https://splfwdprw2:8089/servicesNS/nobody/search/deployment/server/clients/00031e8f6c883544b8079037c5eba9ec</id>
    <updated>2017-04-04T16:14:04-04:00</updated>
    <link href="/servicesNS/nobody/search/deployment/server/clients/00031e8f6c883544b8079037c5eba9ec" rel="alternate"/>
    <author>
      <name>system</name>
    </author>
    <link href="/servicesNS/nobody/search/deployment/server/clients/00031e8f6c883544b8079037c5eba9ec" rel="list"/>
    <link href="/servicesNS/nobody/search/deployment/server/clients/00031e8f6c883544b8079037c5eba9ec" rel="remove"/>
    <content type="text/xml">
      <s:dict>
        <s:key name="applications">
          <s:dict>
            <s:key name="all_deploymentclient">
              <s:dict>
                <s:key name="action">Phonehome</s:key>
                <s:key name="archive">/opt/splunk/var/run/tmp/all_deploymentclient/all_deploymentclient-1491320471.bundle</s:key>
                <s:key name="checksum">0</s:key>
                <s:key name="excludeFromUpdate"></s:key>
                <s:key name="failedReason"></s:key>
                <s:key name="issueReload">0</s:key>
                <s:key name="restartSplunkWeb">0</s:key>
                <s:key name="restartSplunkd">1</s:key>
                <s:key name="result">Ok</s:key>
                <s:key name="serverclasses">
                  <s:list>
                    <s:item>all_deploymentclient</s:item>
                  </s:list>
                </s:key>
                <s:key name="size">10240</s:key>
                <s:key name="stateOnClient">enabled</s:key>
                <s:key name="timestamp">Tue Apr  4 11:42:54 2017</s:key>
              </s:dict>
            </s:key>
            <s:key name="all_fwd_outputs_18indexers">
              <s:dict>
                <s:key name="action">Phonehome</s:key>
                <s:key name="archive">/opt/splunk/var/run/tmp/all_fwd/all_fwd_outputs_18indexers-1491320471.bundle</s:key>
                <s:key name="checksum">0</s:key>
                <s:key name="excludeFromUpdate"></s:key>
                <s:key name="failedReason"></s:key>
                <s:key name="issueReload">0</s:key>
                <s:key name="restartSplunkWeb">0</s:key>
                <s:key name="restartSplunkd">1</s:key>
                <s:key name="result">Ok</s:key>
                <s:key name="serverclasses">
                  <s:list>
                    <s:item>all_fwd</s:item>
                  </s:list>
                </s:key>
                <s:key name="size">10240</s:key>
                <s:key name="stateOnClient">enabled</s:key>
                <s:key name="timestamp">Tue Apr  4 11:42:54 2017</s:key>
              </s:dict>
            </s:key>

...I'm attempting to extract any "s:key name=" strings that appear in the first level below the "s:key name="applications" tag. In this example, the strings I'm looking to extract are "all_deploymentclient" and "all_fwd_outputs_18indexers". If additional strings were to appear on the same level, I would want to capture those as well.

I'm working with xml_grep, but I'm unsure as to how I can define the arguments in order get the desired result (as there are multiple instances of the "s:key name=" tag with some of them serving as a type of heading, and others with a value assigned to them).

So, when it's all said and done, the extraction output for this example should be:

all_deploymentclient
all_fwd_outputs_18indexers

How can I accomplish this? Is another utility (such as xpath) required?


Solution

  • After taking into consideration the information provided by @MichaelKay and @knb, I was able to determine a solution. I ended up using xmlstarlet to get the information I needed as follows:

    xmlstarlet sel -T -t -m "//*[local-name()='key'][@name='applications']/*/*/@name" -v . -n <XML filename>
    

    This produced the following output:

    all_deploymentclient
    all_fwd_outputs_18indexers
    

    Thanks to everyone for their contributions!