0

I have an XML color file that I want to transform to a Kotlin equivalent. Given this input file

colors.xml

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
    <!-- Color Scheme -->
    <color name="primary">#YYYYYY</color>
    <color name="primary_variant">#ZZZZZZ</color>
    ...
</resources>

this is the output I'm looking for

Colors.kt

// Color Scheme
val primary = Color(0xFFYYYYYY)
val primaryVariant = Color(0xFFZZZZZZ)
...

I already put together a Python script to do it, but I was interested in the difference in complexity with a shell solution, which I'm not proficient enough to do.

Specifically, what I'm looking for is:

  • Comments gets mapped to Kotlin comments
  • Newlines are maintained, indentation isn't
  • Variable names are converted from snake_case to camelCase
3
  • 2
    Are you sure about "pure bash"? This would mean not being able to even use sed or alike. – FelixJN Apr 27 at 9:11
  • @FelixJN I'm not familiar with shell differences, my bad. Of course anything with sed or awk is fine – Merig Apr 27 at 9:32
  • 1
    Use an xml parser like xmlstarlet, or an xml-parsing library for python. 1. shell is good for running and orchestrating programs that do text-processing (and other) work. It is not good (in fact, it is terrible) at actually doing that work itself. 2. simple line-oriented tools like sed or awk, using regular expressions alone, are not adequate for parsing XML or other structure text - awk is capable of it, but you'll probably have to write your own xml parser - whereas other languages, like perl or python, already have parser libs written, tested, readily available, and in use for years. – cas Apr 27 at 9:40
4

Given the XML document

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<resources>
    <!-- Color Scheme -->
    <color name="primary">#YYYYYY</color>
    <color name="primary_variant">#ZZZZZZ</color>
    <color name="primary_variant">#ZZZZZZ</color>
    <color name="primary_variant_old">#ZZZZZZ</color>
    <color name="primary_variant_new">#ZZZZZZ</color>
</resources>

in file.xml, you could use the xq utility to get the output you want like so:

xq -r '.resources.color[] |
    "val " +
    ( ."@name" | gsub("_(?<a>.)"; .a | ascii_upcase) ) +
    " = Color(" +
    ( ."#text" | sub("#"; "0xFF") ) +
    ")"' file.xml

or, possibly easier to read,

xq -r '.resources.color[] |
        [ ( ."@name" | gsub("_(?<a>.)"; .a | ascii_upcase) ),
          ( ."#text" | sub("#"; "0xFF") ) ] |
        "val " + .[0] + " = Color(" + .[1] + ")"' file.xml

This picks out each color entry and inserts the modified value of the name attribute and the color node's value into a string that is then outputted.

The name attribute is turned into camel-case by converting each _x (where x is any character) into X (upper-case x). The color nodes value then gets its # replaced by 0xFF.

This would output

val primary = Color(0xFFYYYYYY)
val primaryVariant = Color(0xFFZZZZZZ)
val primaryVariant = Color(0xFFZZZZZZ)
val primaryVariantOld = Color(0xFFZZZZZZ)
val primaryVariantNew = Color(0xFFZZZZZZ)

The xq utility is a tool for translation of XML into JSON. The xq tool then becomes a wrapper around the well known jq JSON parser, so jq expressions may be used to modify or generally work with the XML document structure. It is part of the yq utility distribution (originally a YAML parser wrapper around jq), as found at https://kislyuk.github.io/yq/ (the yq utility available via snap on Linux is also a YAML parser, but a quite different tool!)

The xq parser, like most other parsers, discards comments.


For reference, this is the JSON document that xq converts the above XML into:

{
  "resources": {
    "color": [
      {
        "@name": "primary",
        "#text": "#YYYYYY"
      },
      {
        "@name": "primary_variant",
        "#text": "#ZZZZZZ"
      },
      {
        "@name": "primary_variant",
        "#text": "#ZZZZZZ"
      },
      {
        "@name": "primary_variant_old",
        "#text": "#ZZZZZZ"
      },
      {
        "@name": "primary_variant_new",
        "#text": "#ZZZZZZ"
      }
    ]
  }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.