Good Morning
I have several Checkstyle XML reports with identical structure that I need to merge into a single document, the document looks as follows.
<?xml version="1.0" encoding="UTF-8"?>
<checkstyle version="6.15">
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/communication/EMailMessage.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/communication/EMailSender.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/communication/SMSMessage.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/communication/package-info.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/InputValidation.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/InputValidationALL.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/InputValidationINTEGER.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/InputValidationTEXT.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/MenuNavigationEvent.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/SubscriberForUSSD.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/USSDMenuItem.java">
<error line="327" severity="error" message="Line is longer than 120 characters (found 157)." source="com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck"/>
<error line="327" column="133" severity="error" message="',' is not followed by whitespace." source="com.puppycrawl.tools.checkstyle.checks.whitespace.WhitespaceAfterCheck"/>
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/USSDMenuItemManager.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/USSDResponse.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/ussd/package-info.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/DateUtils.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/DbUtils.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/Enumerators.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/IDNumberValidator.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/SimpleHTTP.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/TextParser.java">
</file>
<file name="/media/sf_Google_Drive/Development/av_microservice/av_microservice/av_microservice_commons/src/main/java/za/co/av/ms_commons/utils/package-info.java">
</file>
</checkstyle>
now I have tried to merge using the following code
def list = []
//create new XML file
File newXMLfile= new File("${rootProject.projectDir}/reports/checkStyleCombined.xml" )
new StreamingMarkupBuilder().bind {
mkp.xmlDeclaration([version:'1.0', encoding:'UTF-8', standalone:'no'])
checkstyle {
//get list of all checkstyle reports
def dir = new File("${rootProject.projectDir}/reports/checkstyle")
dir.eachFileRecurse (FileType.FILES) { file ->
list << file
}
//itterate though the list
list.each {
//parse xml file
def gPathResult = new XmlSlurper().parse(it)
//find all "file" nodes in xml file
gPathResult.file.each{
TEST(XmlUtil.serialize(it))
out << it
}
}
}
}.writeTo(newXMLfile.newWriter("UTF-8"))
The issue I have is twofold firstly it seems that I cant use the XmlUtil.serialize method to write my node because it puts a XML declaration on each line and the formatting looks like this.
<TEST><?xml version="1.0" encoding="UTF-8"?><file name="XXXXXX"/>
Secondly you will note in the XML file that there is an element called file. I cant use the name file in the closure because file is a reserved word so I use "TEST" but this is obviously wrong. So My question is simple does anyone know how to do this in a more simple fashion.
So it seems that the approach I was using was not ideal so what I have done is used one of the XML documents as a root document and merged the other documents into it as follows
def list = []
//This is for the checkstyle report!!!!!!
//create new XML file
File newXMLfile= new File("${rootProject.projectDir}/reports/checkStyleCombined.xml" )
//get list of all checkstyle reports
def dir = new File("${rootProject.projectDir}/reports/checkstyle")
dir.eachFileRecurse (FileType.FILES) { file ->
list << file
}
//set the root xml document to the first document is the list
def root = new XmlSlurper().parse(list.first())
//itterate through the list
list.each {
if(it != list.first())
{
//parse xml file
def gPathResult = new XmlSlurper().parse(it)
//find all file nodes in xml file
gPathResult.file.each{
//append node to root node
root.appendNode(it)
}
}
}
//write the node to file
newXMLfile.withWriter { outWriter ->
XmlUtil.serialize( new StreamingMarkupBuilder().bind{ mkp.yield root }, outWriter )
}
I hope this helps someone someday as it took me quite a while to figure it out.
Related
How can I share an audio file in Android Studio? I have tried the following so far, but it doesn't work.
button.setOnLongClickListener(OnLongClickListener {
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
var path = "absolute/path"
var uri = Uri.parse(path)
putExtra(Intent.EXTRA_STREAM, uri)
type = "audio/mp3"
}
startActivity(sendIntent)
true
})
Your code seems fine, but I'd suggest you to try this one:
String sharePath = Environment.getExternalStorageDirectory().getPath()
+ "/Soundboard/Ringtones/custom_ringtone.ogg"; //This is the path of your audio file
Uri uri = Uri.parse(sharePath); //Identifier of the audio file (Uniform Resource Identifier)
Intent share = new Intent(Intent.ACTION_SEND); //Create a new action_send intent
share.setType("audio/*"); //What kind of file the intent gets
share.putExtra(Intent.EXTRA_STREAM, uri); //Pass the audio file to the intent
startActivity(Intent.createChooser(share, "Share Sound File")); //Start the intent
If that doesn't work either, make sure that you granted the right permissions in the Manifest.xml file (WRITE_EXTERNAL_STORAGE):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
I suggest you look into how to use a file provider. You'll find that you won't be able to provide the uri of the file directly as you're only allowed to expose its content uri. Have a look at the Generating the Content URI for a File section
This is worked for me
Call this method onClick Button:
fun shareAudioFile(audioFile: File) {
val uri = FileProvider.getUriForFile(applicationContext,
"com.app.package.fileprovider",
File(audioFile)
val shareIntent: Intent = ShareCompat.IntentBuilder.from(this#MainActivity)
.setType("audio/mp3")
.setStream(uri)
.intent
startActivity(Intent.createChooser(shareIntent, "Share Sound File"))
}
I replaced Uri.parse with FileProvider.getUriForFile.
Replace com.app.package with your package.
Add on Android Manifest:
<application ...>
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
<application/>
applicationId is your package
Create file_paths.xml file into xml folder
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
</paths>
Share Any File as below ( Kotlin ) :
first create a folder named xml in the res folder and create a new XML Resource File named provider_paths.xml and put the below code inside it :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files"
path="."/>
<external-path
name="external_files"
path="."/>
</paths>
now go to the manifests folder and open the AndroidManifest.xml and then put the below code inside the <application> tag :
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" /> // provider_paths.xml file path in this example
</provider>
now you put the below code in the setOnLongClickListener :
button.setOnLongClickListener {
try {
val file = File("pathOfFile")
if(file.exists()) {
val uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", file)
val intent = Intent(Intent.ACTION_SEND)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.setType("*/*")
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent)
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
toast("Error")
}
}
I want to include data retrieved from an XMLParser and build a new file using the MarkupBuilder. I'm having trouble figuring out how this would work.
If I'm taking the wrong approach here, such as not using MarkupBuilder and using something else, let me know. Thanks!
C:/file.xml:
<externalData>
<data><nestedData><soOnAndSoForth/></nestedData></data>
</externalData>
Code.groovy:
def writer = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(writer).'root'("id":"foo") {
File content = new File("C:/file.xml")
def externalFile = new XmlParser(false,true,true).parse(content)
// may or may not modify this external data...
externalFile.each { elem -> ${elem} }
'moreData'('id':'myData')
}
println writer.toString()
Expected result:
<root id="foo">
<externalData>
<data><nestedData><soOnAndSoForth/></nestedData></data>
</externalData>
<moreData id="myData">
</root>
What I get:
<root id="foo">
<$ />
<moreData id="myData">
</root>
In Groovy given a GPath I want to find that the path exists in XML document. So that I can set a value for the node. I can use xmlslurper for parsing the document. GPath is a string path represented in slashes format.
Look at example:
def xml = '''
<?xml version="1.0" encoding="UTF-8"?>
<data>
<level0 id="1" t="0">
<level1 id="lev1id01" att1="2015-05-12" val="12" status="0" year="2015" month="05" />
</level0>
</data>
'''
// find all nodes named 'level1'
def level1Nodes = new XmlSlurper().parseText(xml).level0.level1
// display found nodes names
level1Nodes.each { node ->
println "node: ${node.name()}"
}
// Get 'year' attribute value for 'level1' node
def level1YearValue = level1Nodes.each { node ->
println "${node.#year}"
}
Could you be more specific in your question?
Camel version 2.14 Smooks version 1.5.1
I got a message which i want to split and transform, but i need the id from the parent. So I thought about using Smooks, splitting the message, transforming and send each output to a queue. Which will be using freemarker template for the transform.
<!-- Message -->
<data>
<id>123</id> <!-- This is needed in both portal messages -->
<portals>
<portal id="1" />
<portal id="2" />
</portals
</data>
<!-- Msg 1 -->
<portal dataId="123">
<id>1</id>
<portal>
<!-- Msg 2 -->
<portal dataId="123">
<id>2</id>
<portal>
There are plenty of examples. But for example the camel examples does not work, due to "java.lang.ClassNotFoundException: org.apache.camel.component.ResourceBasedComponent" which is a known issue.
An alternative would be using groovy for transformation?
So, how could this easiest be solved?
I don't know about smooks, but you can combine the XSLT transformer with a XPATH splitter to do this.
First, transform the data into the blocks that should make up each message. Do it using XSLT, groovy or whatever you feel comfortable with. Here is a simple stylesheet, to be put into src/main/resources (or any classpath location).
<?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"/>
<xsl:template match="/">
<portals>
<xsl:variable name="dataId" select="/data/id"/>
<xsl:for-each select="/data/portals/portal">
<portal dataId="$dataId">
<xsl:attribute name="dataId">
<xsl:value-of select="/data/id"/>
</xsl:attribute>
<id><xsl:value-of select="#id"/></id>
</portal>
</xsl:for-each>
</portals>
</xsl:template>
The Camel route: First the transform, then splitter. The "to" can be whatever, like a seda/direct for further processing or the target protocol.
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file:data"/>
<to uri="xslt:transform.xslt"/>
<split>
<xpath>portals/portal</xpath>
<to uri="log:foo.bar?level=INFO"/>
</split>
</route>
In groovy it can be done this way:
import groovy.util.XmlSlurper
import groovy.xml.MarkupBuilder
def xml = """
<data>
<id>123</id>
<portals>
<portal id="1" />
<portal id="2" />
</portals>
</data>
"""
def slurped = new XmlSlurper().parseText(xml)
def msgId = slurped.id
def portalIds = slurped.portals.portal.#id*.text()
def portalXmls = portalIds.collect { portalId ->
writer = new StringWriter()
portalXml = new MarkupBuilder(writer)
portalXml.doubleQuotes = true
portalXml.portal(dataId: msgId) {
id(portalId)
}
writer
}.each { println it.toString() }
null
How can I log to special folders (e.g. %APPDATA%) using the app.config file?
I can do it programmatically, but I need to be able to use the app.config file for configuration. I have seen a post of using %envFolderPath.It is not available in the latest released version, but only in their latest code.
Below is the code that I setting the log to special folders programmatically.
public void ExampleLog
{
XmlConfigurator.Configure();
var fileName = GetFileName();
var appender = new log4net.Appender.RollingFileAppender
{
Layout = new log4net.Layout.PatternLayout("%d - %m%n"),
File = fileName,
MaxSizeRollBackups = 10,
MaximumFileSize = "100MB",
AppendToFile = true,
Threshold = Level.Debug
};
appender.ActivateOptions();
BasicConfigurator.Configure(appender);
}
private static string GetFileName()
{
const string subPath = "MySubFolder";
var path = String.Format(#"{0}\{1}", Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData), subPath);
const string logName = "Log.txt";
return Path.Combine(path, logName);
}
Pretty sure the syntax for this is available in the current release.
<file type="log4net.Util.PatternString" value="%env{APPDATA}\\MyApp\\Log.txt" />
If you need something more, you can look into option of subclassing the PatternString class, as described here: Log4Net can’t find %username property when I name the file in my appender
Check out the RollingFileAppender configuration sample on the log4net docs (for all the other parameters).
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="log.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="100KB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.SimpleLayout" />
</layout>
</appender>
I've referenced environment variables (including special folders) with the basic log4net variable format ${NAME}. And the file tag doesn't need to have the PatternLayout specified, it's implied.
<file value="${APPDATA}\log.txt" />