2

I have the following xml file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:enabled="false" android:orientation="horizontal" android:id="@id/action_container"
          android:background="@null" android:paddingLeft="4.0dip" android:layout_width="0.0dip"
          android:layout_height="48.0dip" android:layout_weight="1.0"
          style="@style/Widget.Compat.NotificationActionContainer"
          xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:enabled="false" android:layout_gravity="start|center" android:id="@id/action_image"
           android:layout_width="@dimen/notification_action_icon_size"
           android:layout_height="@dimen/notification_action_icon_size" android:scaleType="centerInside"
           android:alpha="0.5"/>
<TextView android:enabled="false" android:textColor="#ffcccccc" 
          android:ellipsize="end"
          android:layout_gravity="start|center" 
          android:id="@id/action_text" android:paddingLeft="4.0dip"
          android:clickable="false" android:layout_width="wrap_content" 
          android:layout_height="wrap_content"
          android:singleLine="true" android:alpha="0.5" 
          style="@style/Widget.Compat.NotificationActionText"/>
</LinearLayout>

I'm trying to remove the extra spaces and line breaks.

This is the result i need:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:enabled="false" android:orientation="horizontal" android:id="@id/action_container" android:background="@null" android:paddingLeft="4.0dip" android:layout_width="0.0dip" android:layout_height="48.0dip" android:layout_weight="1.0" style="@style/Widget.Compat.NotificationActionContainer" xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:enabled="false" android:layout_gravity="start|center" android:id="@id/action_image" android:layout_width="@dimen/notification_action_icon_size" android:layout_height="@dimen/notification_action_icon_size" android:scaleType="centerInside" android:alpha="0.5"/>
<TextView android:enabled="false" android:textColor="#ffcccccc" android:ellipsize="end" android:layout_gravity="start|center" android:id="@id/action_text" android:paddingLeft="4.0dip" android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:alpha="0.5" style="@style/Widget.Compat.NotificationActionText"/>
</LinearLayout>

I tried using this command

sed -i '' 's/^[ \t]*//;s/[ \t]*$//' file.xml

It removed some spaces, but didn't remove the line breaks.

Eventually i want to be able to change for example the ImageView's width (android:layout_width) to 5dip by knowing only its id(@id/action_image).

i want to be able to get an xml element by it's id and change the value of it's other parameters

  • 2
    Why would you need to do this? Any XML parse would treat the two variations of the data as identical. – Kusalananda Feb 17 at 19:13
3

Using xmlstarlet and its fo command:

$ xmlstarlet fo file.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:enabled="false" android:orientation="horizontal" android:id="@id/action_container" android:background="@null" android:paddingLeft="4.0dip" android:layout_width="0.0dip" android:layout_height="48.0dip" android:layout_weight="1.0" style="@style/Widget.Compat.NotificationActionContainer">
  <ImageView android:enabled="false" android:layout_gravity="start|center" android:id="@id/action_image" android:layout_width="@dimen/notification_action_icon_size" android:layout_height="@dimen/notification_action_icon_size" android:scaleType="centerInside" android:alpha="0.5"/>
  <TextView android:enabled="false" android:textColor="#ffcccccc" android:ellipsize="end" android:layout_gravity="start|center" android:id="@id/action_text" android:paddingLeft="4.0dip" android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:alpha="0.5" style="@style/Widget.Compat.NotificationActionText"/>
</LinearLayout>

Use xmlstarlet fo -n to omit the indentation completely.


To modify the android:layout_width attribute of the ImageView node whose android:id attribute is @id/action_image, you definitely do not need to reformat the XML document:

$ xmlstarlet ed -u '//ImageView[@android:id="@id/action_image"]/@android:layout_width' -v "5dip" file.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:enabled="false" android:orientation="horizontal" android:id="@id/action_container" android:background="@null" android:paddingLeft="4.0dip" android:layout_width="0.0dip" android:layout_height="48.0dip" android:layout_weight="1.0" style="@style/Widget.Compat.NotificationActionContainer">
  <ImageView android:enabled="false" android:layout_gravity="start|center" android:id="@id/action_image" android:layout_width="5dip" android:layout_height="@dimen/notification_action_icon_size" android:scaleType="centerInside" android:alpha="0.5"/>
  <TextView android:enabled="false" android:textColor="#ffcccccc" android:ellipsize="end" android:layout_gravity="start|center" android:id="@id/action_text" android:paddingLeft="4.0dip" android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:alpha="0.5" style="@style/Widget.Compat.NotificationActionText"/>
</LinearLayout>

Here we use xmlstarlet to edit the correct attribute of the node we're after. The attribute is selected using the XPath expression

//ImageView[@android:id="@id/action_image"]/@android:layout_width

The //ImageView in the XPath expression will look for ImageView nodes anywhere within the document. To restrict it to only child nodes of the top-level LinearLayout node, use /LinearLayout/ImageView instead.

The -v "5dip" in the command gives the attribute the new value.

Strictly speaking, the question says

i want to be able to get an xml element by it's id [...]

i.e., without knowing the node's name. To do that, just change ImageView in the XPath expression to *. That way you'll update all nodes whose android:id matches the given string.

Related:

0

Using awk to change the separators and truncate 2 or more whitespaces to one:

$ awk -v RS="<" -v FS="\n" -v ORS="\n" -v OFS=" " '$0 {$1="<"$1; gsub(/  +/," ",$0); print}' input.xml
0

The awk solution which includes a change of layout_width to 5dip:

awk -v RS='> *\n *' -v ORS='>\n' '/id="@id\/action_image"/{gsub("layout_width=[^ ]*","layout_width=\"5dip\"")}NF=NF' file 

It works in this particular case, but in general these standard linux tools are not suited for processing xml files.

Output:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:enabled="false" android:orientation="horizontal" android:id="@id/action_container" android:background="@null" android:paddingLeft="4.0dip" android:layout_width="0.0dip" android:layout_height="48.0dip" android:layout_weight="1.0" style="@style/Widget.Compat.NotificationActionContainer" xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:enabled="false" android:layout_gravity="start|center" android:id="@id/action_image" android:layout_width="5dip" android:layout_height="@dimen/notification_action_icon_size" android:scaleType="centerInside" android:alpha="0.5"/>
<TextView android:enabled="false" android:textColor="#ffcccccc" android:ellipsize="end" android:layout_gravity="start|center" android:id="@id/action_text" android:paddingLeft="4.0dip" android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:alpha="0.5" style="@style/Widget.Compat.NotificationActionText"/>
</LinearLayout>
0

One quick hack for this limited html code is the following:

$ perl -F'(?m:^<|>$)' -0777 -ane '
   pop @F;
   print $_, qw[< >][$|--] for map { s/\n\h+/ /gr } @F;
   print "\n";
 ' input.html

Output:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:enabled="false" android:orientation="horizontal" android:id="@id/action_container" android:background="@null" android:paddingLeft="4.0dip" android:layout_width="0.0dip" android:layout_height="48.0dip" android:layout_weight="1.0" style="@style/Widget.Compat.NotificationActionContainer" xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:enabled="false" android:layout_gravity="start|center" android:id="@id/action_image" android:layout_width="@dimen/notification_action_icon_size" android:layout_height="@dimen/notification_action_icon_size" android:scaleType="centerInside" android:alpha="0.5"/>
<TextView android:enabled="false" android:textColor="#ffcccccc" android:ellipsize="end" android:layout_gravity="start|center" android:id="@id/action_text" android:paddingLeft="4.0dip" android:clickable="false" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:alpha="0.5" style="@style/Widget.Compat.NotificationActionText"/>
</LinearLayout>

using the sed editor also we can perform the same:

$ sed -e '
   /^<.*>$/b
   /^</,/\/\{0,1\}>$/!b
   H;/^</h;/\/\{0,1\}>$/!d;g
   s/[[:blank:]]*\n[[:blank:]]*/ /g
 ' input.html
-1

You can try with below command to remove extra spaces and blanklines

sed -r "s/+//g" filename|sed '/^$/d'

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.