So here's my XML output:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
android:compileSdkVersion="23"
android:compileSdkVersionCodename="6.0-2438415"
package="com.mycompany.myapp"
platformBuildVersionCode="23"
platformBuildVersionName="6.0-2438415"
>
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="28"
>
</uses-sdk>
<!-- Read the contents of your shared storage -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
>
</uses-permission>
<!-- Modify or delete the contents of your shared storage -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
>
</uses-permission>
<application
android:theme="@7F1001D3"
android:label="@7F0F001B"
android:icon="@7F0D0000"
android:allowBackup="false"
android:supportsRtl="true"
android:roundIcon="@7F0D0001"
android:appComponentFactory="androidx.core.app.CoreComponentFactory"
>
<activity
android:name="com.mycompany.myapp.MainActivity"
android:configChanges="screenSize|orientation"
>
<intent-filter
>
<action
android:name="android.intent.action.MAIN"
>
</action>
<category
android:name="android.intent.category.LAUNCHER"
>
</category>
</intent-filter>
</activity>
</application>
</manifest>
As you can see, it's already indented, and each attribute inside tag starting in a newline, but it has weird end tags, such as:
<tag
prefix:name="str"
>
</tag>
or:
<tag
prefix:name="str1"
prefix:name2="str2"
>
</tag>
instead of:
<tag prefix:name="str" />
or:
<tag
prefix:name="str1"
prefix:name2="str2" />
My question is, how to prettify XML, with each attribute inside tag starting in a newline (except when there's only one attribute in tag), end tags correction and without comments omitting? Here you can see my desired output:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
android:compileSdkVersion="23"
android:compileSdkVersionCodename="6.0-2438415"
package="com.mycompany.myapp"
platformBuildVersionCode="23"
platformBuildVersionName="6.0-2438415">
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="28" />
<!-- Read the contents of your shared storage -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Modify or delete the contents of your shared storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:theme="@7F1001D3"
android:label="@7F0F001B"
android:icon="@7F0D0000"
android:allowBackup="false"
android:supportsRtl="true"
android:roundIcon="@7F0D0001"
android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<activity
android:name="com.mycompany.myapp.MainActivity"
android:configChanges="screenSize|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Tried to use various prettifiers, such as Java's transformer, Apache Xerces's XML Serializer and etc.
Java's transformer doesn't correct end tags. However, Apache Xerces corrects end tags, comments don't omit, but each attribute inside tag don't start in a newline.
Or maybe I could try to correct end tags in string level if the output is already indented?
XML is always outputted in the same format.
CodePudding user response:
Every XML indenter/formatter has its own way of doing this and your only options are (a) to try them all until you find one that matches your personal preferences, or (b) to write your own.
Saxon's serializer (caveat: my product) is probably more customizable than most. But the more advanced features only come in the commercial editions.
CodePudding user response:
So here's what I did: I've written XML prettifier for my XML outputter based on a regex replacing. Here's the code (uses the Apache Commons IO to write string into file):
private static void prettyPrint(File in) throws Throwable {
String file = new String(Files.readAllBytes(Paths.get(in.toString())));
Pattern p = Pattern.compile("\\s >\\s </. >");
Matcher m = p.matcher(file);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, " />");
}
m.appendTail(sb);
FileUtils.writeStringToFile(in, sb.toString());
prettyPrint2(in);
}
private static void prettyPrint2(File in) throws Throwable {
String file = new String(Files.readAllBytes(Paths.get(in.toString())));
Pattern p = Pattern.compile("\\s >");
Matcher m = p.matcher(file);
StringBuffer sb = new StringBuffer();
while (m.find()) {
m.appendReplacement(sb, ">");
}
m.appendTail(sb);
FileUtils.writeStringToFile(in, sb.toString());
}
Notice the \\s >\\s </. >
pattern. It'll convert this
>
</foo>
to a simplified end tag: />
like this:
<foo
bar="value1"
baz="value2" />
The \\s >
pattern corrects for no reason floating >
here:
<foo1
bar="value1"
baz="value2"
>
<foo2
bar="value1"
baz="value2"
>
</foo2>
</foo1>
to his home:
<foo1
bar="value1"
baz="value2">
<foo2
bar="value1"
baz="value2">
</foo2>
</foo1>
With both regex combined, i get my desired result:
<foo1
bar="value1"
baz="value2">
<foo2
bar="value1"
baz="value2" />
</foo1>
Works like a charm. Also thanks to everybody who tried to help me. Glad to hear your opinions.