0

I can't seem to find exactly how to do this. I have this XML file

<session>
  <translations>
   <translation>
      <inside>198.18.133.1</inside>
      <name>adfs.domain1.com</name>
    </translation>
    <translation>
      <inside>198.18.135.60</inside>
      <name>hds.domain2.com</name>
    </translation>
   </translations>
 </session>

and I want to extract the domain from a particular name node based on the string found in the inside node. As you can see I have multiple name and inside nodes. With the following Bash file I can extract the first instance of name

#!/bin/bash
domain="$(echo "cat /session/translations/translation/name/text()" | xmllint --nocdata --shell session.xml | sed '1d;$d')"
domain="${domain:5}"
printf '%s\n' "Domain is: $domain"

This will give me domain1.com.

Sometimes I could have more translations or less and they aren't always in the same order. So I need a way to pull the name IF the inside node matches 198.18.133.1 or pull the name IF the inside node matches 198.18.135.60, etc.

7
  • Have you considered XSLT? You can do it with Java SE and Saxonica HE. Commented Sep 10, 2018 at 20:31
  • @jeff6times7, there's no need for a JVM -- every modern Linux distro (and MacOS) ships with xsltproc. Maybe if you needed something newer than 1.0, but this query doesn't need a modern version of the standard. Commented Sep 10, 2018 at 20:31
  • @CharlesDuffy Are you sure Jason's using linux? Commented Sep 10, 2018 at 20:32
  • Even if it's not Linux, it's something that ships with bash, and that narrows it down enough. xsltproc is pretty much ubiquitous these days -- it's widely used for compiling documentation to HTML at build time. If you have a recent (last-15-years) UNIX-family system with a compiler/development toolchain, it's more more common to not have a JVM than to not have xsltproc. Commented Sep 10, 2018 at 20:33
  • 2
    Incidentally, XMLStarlet compiles command-line queries down to XSLT -- one can (in the relevant usage modes) ask it to output an XSLT template which will perform the same operation given on the command line. Commented Sep 10, 2018 at 20:39

1 Answer 1

1

Your current XPath expression, of:

/session/translations/translation/name/text()

...can easily be changed to:

/session/translations/translation[inside="198.18.133.1"]/name/text()

...to perform the desired filtering.


Doing this with XMLStarlet, rather than XMLLint, might look more like:

xmlstarlet sel -t -m '/session/translations/translation[inside="198.18.133.1"]/name' -v . -n

If adding the -C argument to the sel subcommand, it will emit the XSLT template which it's evaluating under-the-hood, which you could run anywhere with xsltproc installed, including systems without XMLStarlet:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/">
    <xsl:for-each select="/session/translation/translation[inside=&quot;198.18.133.1&quot;]/name">
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="."/>
      </xsl:call-template>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, I tried to change the XPath expression and it gave me this error. "XPath error : Invalid predicate /session/translations/translation[inside=198.18.133.1]/name/text() ^ xmlXPathEval: evaluation failed /session/translations/translation[inside=198.18.133.1]/name/text(): no such node
the ^ was under the period after 18 if that helps
See how it's just inside=198.18.133.1, not inside="198.18.133.1", in the error? You don't want to let the shell eat your quotes.
...there's a reason I used single quotes on the outside in this answer -- so the double-quotes inside them would be preserved.
Sweet yes that was it! Thanks so much for the quick response! Works like a champ!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.