I have an xml like below.
<Students college="SGS">
<Student id="001" name="ABC"/>
<Student id="002" name="XYZ"/>
<Students/>
<Students college="SPM">
<Student id="001" name="PQR"/>
<Student id="002" name="LMN"/>
<Students/>
and I want name of the student of the SGS college whose id is 001 using apache ant.
So how can I get this without using extra jar like xmltask.jar etc
The simplest solution is to use XPath to get this information. In Ant there is no built-in task to fetch XML data using XPath expressions. You would need to use tasks provided in external libraries:
https://code.google.com/p/ant-xpath-task/wiki/Introduction
http://ant.apache.org/external.html
Related
Good afternoon,
I am working with Java Saxon 9.8.0.4. I would like to use EXPath File Module function "file:list" with its third "pattern" parameter. But I am in doubt, which style of pattern is supported.
I read both Saxon documentation and EXPath documentation. But I do not know, which patterns are supported in Saxon 9.8.0.4. It would be great to support regular expression, but I understand it is overkill for most users. I tried several blind tests, but just * and ? wildchars works for me as defined in EXPath documentation.
Yes, I can quite easily do regexp postprocessing in for-each, but to know more about list function could help.
Thank You in advance for Your help, Stepan
P.S: My use-case is to get all files without extension ("test" and not "test.txt") recursively from large and deep directory structure and process all of matching files with XSL-T 3.0. Most of such files have identical fileName and thus I can not do "copy to one folder" pre-processing for Saxon's -s:directory -o:directory one time invocation and invocation of Java (Saxon) for each file is of cource terrible time overhead. So I would like to read all matching files into sequence and process each item of such sequence using for-each (files are text ones and I read them using unparsed-text). And no, GAWK is not solution, as I have all transformation infrastructure from XML to SQL already in XSL-T, because 95 % of files are XMLs.
--ADDED code and explanation below:
Example of my test files.
XML file "a.xml":
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="a.xsl"?>
<root/>
XSL-T file "a.xsl":
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:saxon="http://saxon.sf.net/"
xmlns:expathFile="http://expath.org/ns/file"
exclude-result-prefixes="xs saxon"
version="3.0">
<xsl:output method="text" />
<xsl:template match="/root">
<xsl:variable name="list" select="expathFile:list('C:\temp\temp\test\', false(), '^.*$')"/>
<xsl:for-each select="$list">
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
My folder "C:\temp\temp\test\" contains 6 test files: "a.txt", "b.txt", "c.txt", "e", "f", "g".
But after testing of online Java RegExp tester on "http://www.regexplanet.com/advanced/java/index.html" I have found, that the problem is solely on my side, because Java regular expression behaves little different than PCRE (Perl), sed, gawk regular expressions. So it is my fault and I need to learn Java regular expression.
Saxon uses the same code for this pattern as for the filter in select="pattern" in collection URIs, which is described at http://www.saxonica.com/documentation/index.html#!sourcedocs/collections
Extracting the relevant details:
The pattern used in the select parameter can use glob-like syntax, for
example *.xml selects all files with extension "xml". More generally,
the pattern is converted to a regular expression by prepending "^",
appending "$", replacing "." by "\.", "*" by ".*", and "?" by ".?",
and it is then used to match the file names appearing in the directory
using the Java regular expression rules. So, for example, you can
write ?select=*.(xml|xhtml) to match files with either of these two
file extensions. Note however, that special characters used in the URL
(that is, characters such as backslash and curly braces that are not
allowed in the query part of a URI) must be escaped using the %HH
convention. For example, vertical bar needs to be written as %7C. This
escaping can be achieved using the encode-for-uri() function.
Note that Saxon's collection() function now also supports match=pattern in the URI, where the pattern is a standard XPath 3.1 regular expression.
I have a simple XML file like this
<?xml version="1.0"?>
<catalog>
<timezone>
<name>UTC-11:00</name>
<place>
<value>American Samoa</value>
<value>Samoa</value>
</place>
</timezone>
<timezone>
<name>UTC-10:00</name>
<place>
<value>Honolulu</value>
<value>Tahiti</value>
</place>
</timezone>
</catalog>
What is the canonical/standard way to parse this in iOS? I want to save "names" and "places" for each name.
NSXMLParser is already built in. You should look at this article for a more thorough comparison.
http://www.raywenderlich.com/553/xml-tutorial-for-ios-how-to-choose-the-best-xml-parser-for-your-iphone-project
It is NSXMLParser. Official documentation
I need to use variable in WIX localization file WIXUI_en-us.wxl.
I tried use it like this:
<String Id="Message_SomeVersionAlreadyInstalled" Overridable="yes">A another version of product $(var.InstallationVersionForGUI) is already installed</String>
But it doesn't work. And when I declared property and used it this way:
<String Id="Message_SomeVersionAlreadyInstalled" Overridable="yes">A another version of product [InstallationVersionForGUI] is already installed</String>
doesn't work either.
Where was I wrong?
Thanks for help and your time.
Localization strings are processed at link time, so you can't use $(var) preprocessor variables. Using a [property] reference is supported, as long as the place where the localization string is used supports run-time formatting (e.g., using the Formatted field type).
Your second method should work just fine. This is the same method used by the default .wxl files.
For example, in your .wxl file you would declare your string:
<String Id="Message_Foo">Foo blah blah [Property1]</String>
And in your .wxs file, you declare the property. If you wish, you can declare the property to match a WiX variable (which it sounds like you're trying to do)
<Property Id="Property1">$(var.Property1)</Property>
I was trying to get localization file to use variables. Came across this post:
There are different layers of variables in WiX (candle's preprocessor
variables, Light's WixVariables/localization variables/binder
variables, and MSI's properties). Each have different syntax and are
evaluated at different times:
Candle's preprocessor variables "$(var.VariableName)" are evaluated
when candle runs, and can be set from candle's commandline and from
"" statements. Buildtime environment
properties as well as custom variables can also be accessed similarly
(changing the "var." prefix with other values).
Light's variables accessible from the command-line are the
WixVariables, and accessing them is via the "!(wix.VariableName)"
syntax. To access your variable from your commandline, you would need
to change your String to: This build was prepared on
!(wix.BuildMachine)
If you instead need to have the BuildMachine value exist as an MSI
property at installation time (which is the "[VariableName]" syntax)
you would need to add the following to one of your wxs files in a
fragment that is already linked in:
Now, the environment variable COMPUTERNAME always has held the name of
my build machines in the past, and you can access that this way:
$(env.COMPUTERNAME). So, you can get rid of the commandline addition
to light.exe and change your wxs file like this:
<WixProperty Id="BuildMachine" Value="$(env.COMPUTERNAME)"/>
Preprocessor variables $(var.VariableName) are are processed at link time, so ideally you would use [PropertyName] which would be defined on the main Product element.
The issue sometimes is that property is not yet defined, for instance using the product name on the localization file seems not posible.
This solution was done aiming to only type the product name once given "Super product" as product name:
In case of running through visual studio extension:
Project properties -> Build -> Define variables -> "MyProductName=Super product" (No quotes)
In case of runing from cmd or some other place:
On Light.exe, add -d"MyProductName=Super product"
Into the localization .wxl file:
<String Id="Description" Overridable="yes">Description of !(wix.MyProductName)
to make it more interesting</String>
I have an aditional config file .wxi I include on other files to have some vars, for instance, here i had hardcoded the value but now it's harcoded on the variable definition and I use the given value:
<?xml version="1.0" encoding="utf-8"?>
<Include>
<!-- Define the product name preprocesor variable -->
<?define ProductName="!(wix.ProductNameDefVar)" ?>
<!-- From this point, can use the preprocesor var -->
<?define ProductName_x64="$(var.ProductName) (64bit)" ?>
<?define ProductName_x32="$(var.ProductName) (32bit)" ?>
<?define CompanyDirName = "My company name" ?>
</Include>
Finally, the place where the localization value where the localization text was not interpolating, is like this:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<!-- Include the config file with the preprocesor var -->
<?include $(sys.CURRENTDIR)\Config.wxi?>
<!-- Main product definition -->
<Product Id="$(var.ProductCode)"
Name="$(var.ProductName)"
Language="!(loc.Language)"
Version="$(var.BuildVersion)"
Manufacturer="!(loc.Company)"
UpgradeCode="$(var.UpgradeCode)">
<!-- Package details -->
<!-- Here, Description was not interpolating -->
<Package InstallerVersion="200"
Compressed="yes"
InstallScope="perMachine"
Platform="$(var.Platform)"
Manufacturer="!(loc.Company)"
Description="!(loc.Description)"
Keywords="!(loc.Keywords)"
Comments="!(loc.Comments)"
Languages="!(loc.Language)"
/>
[...]
I have multiple bindings(xjb files) in the gradle project. When generating JAXB classes for a xsd(C.xsd). I want to use the previously generated binding files for A.xjb & B.xjb since C.xsd refers to A.xsd & B.xsd
The below ant xjc task works if I don't have anyother bindings in same path but I want specify explicity A.xjb & B.xjb bindings. How to go about same, I tried various options but nothing seems working. Any help greatly appreciated.
ant.xjc(destdir : '${jaxbDest}', removeOldOutput:'yes', extension:'true') {
arg(line:'-Xequals -XhashCode -XtoString -Xcopyable')
schema(dir:'src/main/schema', includes:'C.xsd')
binding(dir:'src/main/schema', includes:'*.xjb)
}
Thanks
Ravi
According to this documentation for the ant xjc task -
"To specify more than one external binding file at the same time, use a nested element, which has the same syntax as fileset."
In gradle it would look like this:
binding(dir:'src/main/schema'){
include(name:'A.xjb')
include(name:'B.xjb')
}
I think this would also work:
binding(dir:'src/main/schema', includes:'A.xjb,B.xjb')
I'm trying to automize my android build process. For that, I want to change the app name in an XML file. the code is something like this
<resources>
<string name="app_name">Realta Connections</string>
</resources>
Now I want to replace the name 'Realta Connections' by something else at build time, a name which I would give at build time. The name can be 'Realta Connections' or anything else, so I need to detect the name="app_name" and replace the content inside it. I tried looking for how to do it but couldn't find the precise way. How can I do that? Please help.
It is probaly easiest to have a fixed value, which will be replaced. This will allow the use of the replace task:
You need replacetoken/replacevalue and the Strings inside ![CDATA[]] because of the xml characters.
<replace casesensitive="false"
file="../KS.build/ivy.properties">
<replacetoken><![CDATA[<string name="app_name">Realta Connections</string>]]></replacetoken>
<replacevalue><![CDATA[<string name="app_name">Something else</string>]]></replacevalue>
</replace>
Otherwise there is no normal ant solution (repleaceregex doesn't allow nested CDATA replacements).
Links:
Ant replace task
I know this question is quite old, but here is an idea. This seems like it's not really a purely ant solution, but you can embed a script in ant using the <scriptdef> tag.
Here is a function you can use to search for something in an XML file and store the result in a property:
<scriptdef name="xpath-query" language="javascript">
<attribute name="query"/>
<attribute name="xmlfile"/>
<attribute name="property"/>
<![CDATA[
importClass(java.io.FileInputStream);
importClass(javax.xml.xpath.XPath);
importClass(javax.xml.xpath.XPathConstants);
importClass(javax.xml.xpath.XPathFactory);
importClass(org.xml.sax.InputSource);
importClass(java.lang.System);
var exp = attributes.get("query");
var filename = attributes.get("xmlfile");
var xpath = XPathFactory.newInstance().newXPath();
var input = new InputSource(new FileInputStream(filename));
var value = xpath.evaluate(exp, input, XPathConstants.STRING);
self.project.setProperty( attributes.get("property"), value );
System.out.println("Copied this value:" + value + " to this property:" + attributes.get("property"));
]]>
</scriptdef>
Then you could get the current name of the app by using the xpath-query task you just defined:
<xpath-query query='pathToResources\resources\string[#name="app_name"]' xmlFile="app.xml" property="appName" />
Then the app name will be stored in the property appName.
From there you could do regex replace on the xml file using the app name.
<replaceregexp file="app.xml" match="${appName}" replace="${newAppName}" />
The potential down-side of this particular approach is that if you have the same app name string somewhere else in the XML file the regex replace may replace something you didn't intend.
You could probably define the <scriptdef> to do the replacement rather than just storing what was found in a property, but I had this portion of code handy already.
When dealing with XML in ANT I always recommend the xmltask. For your requirement see xml task manual replace
A little Xpath knowledge won't hurt, see:
http://zvon.org/xxl/XPathTutorial/
http://www.w3schools.com/xpath/
try this code, it works for me
<target name="change-app-name">
<replaceregexp file="res/values/strings.xml" match='name="app_name"(.*)'
replace='name="app_name">Something Else<\/string>'/>
</target>