I have base64 encoded contents (image file) and I'd like to write this to an external file using XSLT/XPath 2.0.
This is my input file
<root>
<img>iVBORw0KGgoAAAANSUhEUgAABAAAAAMAAQMAAACAdIdOAAAABlBMVEUAAAD///
+l2Z/dAAABpElEQVR42u3OQQ0AMAgEsHOAf7Wbhn0GIa2C5jSLgICAgICAgICAgI
CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI
CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMDgQB6UgICAgICAgICAgICAgI
CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI
CAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI
CAgICAgICAgICAgICAgICAgICAgICAgMDKwB8CAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAu2BC6XQXOr9fnZDAAAAAElFTkSuQmCC</img>
</root>
And this my my attempt to write the file:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:file="http://expath.org/ns/file">
<xsl:template match="img">
<myimg>
<xsl:variable name="filename" select="'hello.png'"/>
<xsl:attribute name="filename" select="$filename"/>
<xsl:value-of select="file:write-binary($filename,xs:base64Binary(.))" />
</myimg>
</xsl:template>
</xsl:stylesheet>
But "nothing happens", which means I get an XML file with myimg as the root tag (expected), but no file written into the current directory. What am I supposed to do?
I use Saxon-PE-9.7.0.15 with oXygen XML
Edit: use hello.png as a filename (to lessen the confusion)
It seems a problem related to using Saxon and the EXPath file module inside oXygen because when I run the XSLT outside oXygen with Saxon the file is created in the same directory as the XML input and stylesheet code, however inside oXygen the use of <xsl:message select="'current-dir() ', file:current-dir()"/> indicates the file module uses a different directory to read from and write to.
Related
I am looking for a way to replace a HTML tag with another, but keep the text.
I have a big HTML file, which contains:
<span class="desc e-font-family-cond">fork</span>
I want to replace <span> tag with <strong> tag:
<strong>fork</strong>
Tool doesn't really matter, but I am looking for a CLI way to do it.
I am not looking for a HTML processor, because input is a text file with some HTML code in it (not a clean/valid HTML) and I am manually working with the output (copy, modify, use later in its final place). I just want to save some time with the replace.
I would use GNU sed for this task following way, let file.txt content be
<span class="desc e-font-family-cond">fork</span>
then
sed -e 's/<span[^>]*>/<strong>/g' -e 's/<\/span>/<\/strong>/g' file.txt
output
<strong>fork</strong>
Explanation: firstly replace span starting using <strong>, secondly replace span closing using </strong>.
Consider using Python and a tool like BeautifulSoup to handle HTML. Trying to parse HTML with other tools like sed or awk can lead to terrible places.
As an example:
from bs4 import BeautifulSoup
soup = BeautifulSoup('<li><span class="desc e-font-family-cond">fork</span>')
for spanele in soup.findAll('span'):
spanele.name = 'p'
html_string = str(soup)
print(html_string);
That's lightweight and pretty simple and the html is handled properly with a library that is specifically built to parse it.
Don't use AWK for processing HTML files. If you can turn your HTML file into an XHTML file, you can use xsltproc for an XML transformation as follows:
trans.xsl file:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="span[#class='desc e-font-family-cond']">
<strong><xsl:apply-templates/></strong>
</xsl:template>
</xsl:stylesheet>
CLI command for invoking xsltproc, which has to be installed, obviously:
xsltproc trans.xsl file.html
The standard output of this command is the corrected HTML file as you want to have it.
Using sed:
sed 's,<\(\/\)\?span\(\s\)\?,<\1strong\2,g'
$ echo '<span class="desc e-font-family-cond">fork</span>' | sed 's,<\(\/\)\?span\(\s\)\?,<\1strong\2,g'
<strong class="desc e-font-family-cond">fork</strong>
I'm issuing the command xdg-mime install nv-custom.xml - using this file:
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="text/x-customtest">
<comment></comment>
<glob weight="60" pattern="*...someUnicodeHere"/>
</mime-type>
</mime-info>
Is it possible to use unicode in the glob's pattern field?
I tried Ctrl + Shift + U followed by a code, which works fine, but then the file does not have any effect, whereas it works just fine with "regular" text.
How can I add a custom xmlns in the output when I convert an asciidoc file with AsciiDoctor?
I'd like to add xmlns:xi="http://www.w3.org/2001/XInclude" in the top book tag.
The current implementation seems to generate:
<?xml version="1.0" encoding="UTF-8"?>
<?asciidoc-toc?>
<?asciidoc-numbered?>
<book xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
<info>
<title>title</title>
</info>
</book>
from this:
= title
:lang: en
When I run:
$ asciidoctor -b docbook5 -d book -o out.xml source.txt
There is a built-in attribute xmlns, but it seems to be for docbook 4.5.
The reason I want to use XInclude is to include some xml files from Docinfo files and Passthrough Blocks
With a bit of research inside the asciidoctor code it quickly became clear that the part you'd like to modify is fairly static.
See asciidoctor/converter/docbook5.rb Line 44 for more info.
The best approach is to create a postprocessor extension which modifies the output. The example below is just to show a possible implementation.
Create a file with the following content and call it docbook_postprocessor.rb.
class Docbook5XiPostprocessor < Asciidoctor::Extensions::Postprocessor
def process document, output
if document.basebackend? 'docbook'
input_regex = %r{^(<.*xmlns:xl="http://www.w3.org/1999/xlink") (version="5.0".*>)}
replacement = %(\\1 xmlns:xi="http://www.w3.org/2001/XInclude" \\2)
output = output.sub(input_regex, replacement)
end
output
end
end
Asciidoctor::Extensions.register do
postprocessor Docbook5XiPostprocessor
end
Note: The above extension is for the sake of brevity placed in the same directory as the asciidoctor source file called source.adoc.
The run the asciidoctor command with the -r ./docbook_postprocessor.rb parameters.
$ asciidoctor -r ./docbook_postprocessor.rb -b docbook5 -d book -o - source.adoc
<?xml version="1.0" encoding="UTF-8"?>
<?asciidoc-toc?>
<?asciidoc-numbered?>
<book
xmlns="http://docbook.org/ns/docbook"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:lang="en">
<info>
<title>test</title>
<date>2020-12-19</date>
</info>
</book>
* Above output has been slightly reformatted to eliminate the scrollbar
Creating ruby gem with the above code for easier distribution is a task left to the reader.
Hello is there a way to sort the string names alphabetically in strings.xml ?
It should sort it like this
Before
<string name="ccc">CText</string>
<string name="aaa">AText</string>
<string name="bbb">BText</string>
After
<string name="aaa">AText</string>
<string name="bbb">BText</string>
<string name="ccc">CText</string>
I am using Android Studio 1.5.1
I used AndroidXmlSorter plugin and it works perfectly for me.
How to install:
Go to Android Studio -> Preferences -> Plugins and hit Browse repositories..
Search for AndroidXmlSorter, install and restart your Android Studio. Go to your strings.xml file and hit Ctrl+L. Voila.
Disclaimer: I'm not the author of this plugin, I just found it by chance and I think all the credits should go to the plugin author. The repo is here: https://github.com/roana0229/android-xml-sorter
For anyone else who bumps into this. Copy all the string elements, paste into an Excel spreadsheet sort A-Z and then copy and paste back.
[Sort Android strings.xml in Alphabetical Order]
There is a plugin called Lines Sorter which can sort selected lines or whole files.
2022-09 | Simple plugin free solution:
Android studio includes option to sort lines / reverse lines.
Highlight lines of code to be sorted
unsorted lines
Edit > sort lines or Edit > reverse lines
sort line
Enjoy (reverse) alphabetical order
sorted lines
Sadly AndroidXmlSorter doesn't work for me when sorting multi-line strings.
My solution: Sort the strings.xml according to my android_strings_format.xslt (with xsltproc) and reformat it (with xmllint).
Cons: You have to execute a script. Therefore, it is not a true native feature of Android Studio. But you can easily execute scripts in Android Studio.
The script:
#!/bin/sh
sort_xml_file() {
xsltproc --output "$1" android_strings_format.xslt "$1"
export XMLLINT_INDENT=" "
xmllint --format --encode "utf-8" --output "$1" "$1"
}
sort_xml_file "src/main/res/values/strings.xml"
The android_strings_format.xslt file:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output
method="xml"
version="1.0"
encoding="UTF-8"
indent="yes"
omit-xml-declaration="yes"/>
<xsl:template match="/resources">
<resources>
<xsl:for-each select="string">
<xsl:sort select="#name"/>
<string name="{#name}">
<xsl:copy-of select="#* | node()"/>
</string>
</xsl:for-each>
</resources>
</xsl:template>
</xsl:stylesheet>
Works on Manjaro Linux x64.
EDIT: I have found a way to prevent multi-line text. I can enclose the text with quotes. <string name="available_version_error">"<u>ERRORa</u>"</string>
I used a XML formatter with an xslt definition - but this was too complex if you also uses plurals.
My solution: writing my own Python script:
import re
# add your files here
strings_files = ["path/to/strings.xml"]
# 1. transform the strings.xml file to a dict
# 2. sort the dict
# 3. transform the dict to a strings.xml file
def sort_strings_xml_file(path_to_file: str):
entries = dict()
current_entry_name = None
# read entries from strings.xml file
with open(path_to_file, "r") as file:
for line in file.readlines():
# a new entry was found in the strings.xml file
if line.strip().startswith("<string ") or line.strip().startswith("<plurals "):
current_entry_name = re.search(r'name="(.+)"', line).group(1)
entries[current_entry_name] = ""
# store content for the current entry
if current_entry_name is not None:
entries[current_entry_name] += line
# stop recording for the current entry
if line.strip().endswith("</string>") or line.strip().endswith("</plurals>"):
current_entry_name = None
entries = dict(sorted(entries.items()))
# write results back to the strings.xml file
with open(path_to_file, "w") as file:
file.write(('<?xml version="1.0" encoding="utf-8"?>'
'<resources>'
f'{"".join(entries.values())}</resources>'))
print(f"{path_to_file} was sorted")
for strings_file in strings_files:
sort_strings_xml_file(strings_file)
i would turn them to ASCII then sort that one and turn them back to string, very easy and very effective
Update: Easiest way is: Ctrl+A then Ctrl+Alt+L
For configuration: In Android studio, you can quickly sort XML code by following step:
Select all XML code in a file by Ctrl+A
Use combination: Ctrl+Alt+Shift+L
Select "Selected text" + "Rearrange code" Then Press RUN
I am using XSLT params to set an absolute path in an attribute at runtime using Xalan-C. Basically, my input XML is something like this :-
<root xmlns="initial">
<!-- document goes here -->
</root>
My stylesheet is :-
<xsl:stylesheet version="1.0" xmlns:s="initial" xmlns="final" />
<xsl:param name="default_data_location">/path/to/some/location</xsl:param>
<xsl:template match="//s:*">
<xsl:element name="{local-name()}" namespace="final">
<xsl:attribute name="dataLocation">
<xsl:value-of select="concat($default_data_location, '/datafile')"/>
</xsl:attribute>
</xsl:element>
</xsl:template>
<!-- rest of the stylesheet -->
</xsl:stylesheet>
Thus, my desired output XML when I run it as :-
Xalan foo.xml foo.xsl
should be (this is the part that works) :-
<root xmlns="final" dataLocation="/path/to/some/location/datafile">
<!-- document goes here -->
</root>
And when I run it as :-
Xalan -p default_data_location /some/other/path foo.xml foo.xsl
it should be (and this is the part that doesn't work) :-
<root xmlns="final" dataLocation="/some/other/path/datafile">
<!-- document goes here -->
</root>
If I try to set this param at the command line, however, it gives me the following XML :-
<root xmlns="final" dataLocation="/datafile">
<!-- document goes here -->
</root>
What should I be doing?
The parameter value seems to be an XPath expression so you need to make sure you pass in an XPath string and you might need to double quotes to make sure the command line shell does not get into your way so doing Xalan -p default_data_location "'/some/other/path'" foo.xml foo.xsl should work. At least that's my reading of the documentation at http://xml.apache.org/xalan-c/commandline.html, I don't have Xalan-C to test.