separator in string template - stringtemplate

I have the following code in a stringtemplate file:
(1) Module $component$ = new Module(new GeometryDescription[] {$shapes;separator=", "$});
which i know is wrong as what I would like is to be able to generate multiple of this line
so that when i call a list of components Component1(North, part1, part2)
Component2(North, part1, part2,part3)
i get the following:
Module North = new Module(new GeometryDescription[] {part1,part2});
Module South = new Module(new GeometryDescription[] {part1,part2,part3});
how can i write sentence (1) to be able to do that
thanks

You need to wrap (1) in a template and then map that template across your list of components.

Related

Doxygen - Generating Dynamic Groups with an Alias Command with a parameter

I'm looking to create a group hierarchy automatically, by having some kind of Alias command. E.g. I want the groups
Extension Methods
String Extensions
Stream Extensions
...
to be created with doxygen comments such as
/** Documentation for the method
* \extension{string}
*/
public void ExtensionMethod(this string str){
...
}
Where \extension{string} would map to something like
\addtogroup stringExtensions string Extensions
\ingroup ExtnMethods
Unfortunately this means that all the documentation written for the method gets associated with the group instead.
The closest I've got is that if you have something like
/** \addtogroup stringExtensions string Extensions
* \ingroup ExtnMethods
* \#{
* \#}
*/
/** \ingroup stringExtensions
* Documentation for the method
*/
public void ExtensionMethod(this string str){
...
}
it would work, but this needs the 2 separate comment blocks and I can't find any way to do that using an Alias.
I know that something can probably be achieved with an inputfilter - but I'm hoping something far simpler can be achieved.
I've found an answer using inputfilters that was neater than I first supposed - parse the entire file looking for \extension{...}, replacing it with an appropriate \ingroup command, and then append the desired \addgroup commands at the bottom of the file.
This can then be run as an inputfilter
The following is a python script that does this. Note that it doesn't check that what it's replacing is actually within a doxygen comment, but it's good enough for my purposes.
#!python
import sys, re
if(len(sys.argv) != 2):
print "Need exactly one argument, the file to filter"
exit(1)
extnFinder = re.compile("\\\\extension{(\w+)}")
extnTypes = set();
filename = sys.argv[1]
fileIn = open(filename, "r")
line = fileIn.readline()
def extnSub(matchobj):
extnTypes.add(matchobj.group(1))
return "\ingroup %(extn)sExtensions" % {'extn':matchobj.group(1)}
while line:
matches = extnFinder.findall(line)
sys.stdout.write(re.sub(extnFinder,extnSub,line))
line = fileIn.readline()
for extn in extnTypes:
print "\n\n/**\\addtogroup %(extn)sExtensions %(extn)s Extensions\n\\ingroup ExtnMethods\n */\n" % {'extn':extn}

VTD-XML creating an XML document

I am a bit confused on how to do this, all of the docs / examples show how to read and edit xml docs but there doesn't seem to be any clear way of creating an xml from scratch, I would rather not have to ship my program with a dummy xml file in order to edit one. any ideas? thanks.
What you could do instead would be to just hard-code an empty document like this:
byte[] emptyDoc = "<?xml version='1.0' encoding='UTF-8'?><root></root>".getBytes("UTF-8");
And then use that to create your VTDGen and XMLModifier, and start adding elements:
VTDGen vg = new VTDGen();
vg.setDoc(emptyDoc);
vg.parse(true);
VTDNav vn = vg.getNav();
XMLModifier xm = new XMLModifier(vn);
// Cursor is at root, update Root Element Name
xm.updateElementName("employee");
xm.insertAttribute(" id='6'");
xm.insertAfterHead("<name>Bob Smith</name>");
vn = xm.outputAndReparse();
// etc...

parsing tcx document using xdocument selectsinglenode

I am trying to parse an TCX document similiar to the one used in this post: Import TCX into R using XML package
Only I'm trying to use XmlDocument.SelectNodes and SelectSingleNode instead of getNodeSet. The line with xmlns looks like this:
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">
If I remove the xmlns and just have , I can parse it without any problems.
My (vb.net) code:
Dim tcxXmlDocument As New System.Xml.XmlDocument()
tcxXmlDocument.Load(tcxFile)
Dim xmlnsManager = New System.Xml.XmlNamespaceManager(tcxXmlDocument.NameTable)
Dim trackpoints As New List(Of Trackpoint)
For Each tpXml As System.Xml.XmlNode In tcxXmlDocument.SelectNodes("//Trackpoint", xmlnsManager)
Dim newTrackpoint As New Trackpoint
With newTrackpoint
.Time = tpXml.SelectSingleNode("Time").InnerText
.LatitudeDegrees = tpXml.SelectSingleNode("Position/LatitudeDegrees").InnerText
.LongitudeDegrees = tpXml.SelectSingleNode("Position/LongitudeDegrees").InnerText
.HeartRateBpm = tpXml.SelectSingleNode("HeartRateBpm").InnerText
End With
trackpoints.Add(newTrackpoint)
Next
How can I configure the XmlNamespaceManager so that I can access the nodes in such a tcx document?
Thanks,
Jason
Use the XmlNamespaceManager.AddNamespace() method to associate a preffix (say "x") with the namespace "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2".
Then in your XPath expression, pefix every element name with the "x" prefix.
Replace this:
//Trackpoint
with:
//x:Trackpoint
Replace this:
Time
with:
x:Time
Replace this:
Position/LatitudeDegrees
with:
x:Position/x:LatitudeDegrees
Replace this:
Position/LongitudeDegrees
with:
x:Position/x:LongitudeDegrees
Finally, replace this:
HeartRateBpm
with:
x:HeartRateBpm

The ':' character, hexadecimal value 0x3A, cannot be included in a name

I saw this question already, but I didnt see an answer..
So I get this error:
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
On this code:
XDocument XMLFeed = XDocument.Load("http://feeds.foxnews.com/foxnews/most-popular?format=xml");
XNamespace content = "http://purl.org/rss/1.0/modules/content/";
var feeds = from feed in XMLFeed.Descendants("item")
select new
{
Title = feed.Element("title").Value,
Link = feed.Element("link").Value,
pubDate = feed.Element("pubDate").Value,
Description = feed.Element("description").Value,
MediaContent = feed.Element(content + "encoded")
};
foreach (var f in feeds.Reverse())
{
....
}
An item looks like that:
<rss>
<channel>
....items....
<item>
<title>Pentagon confirms plan to create new spy agency</title>
<link>http://feeds.foxnews.com/~r/foxnews/most-popular/~3/lVUZwCdjVsc/</link>
<category>politics</category>
<dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/" />
<pubDate>Tue, 24 Apr 2012 12:44:51 PDT</pubDate>
<guid isPermaLink="false">http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</guid>
<content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[|http://global.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg<img src="http://feeds.feedburner.com/~r/foxnews/most-popular/~4/lVUZwCdjVsc" height="1" width="1"/>]]></content:encoded>
<description>The Pentagon confirmed Tuesday that it is carving out a brand new spy agency expected to include several hundred officers focused on intelligence gathering around the world.&amp;#160;</description>
<dc:date xmlns:dc="http://purl.org/dc/elements/1.1/">2012-04-4T19:44:51Z</dc:date>
<feedburner:origLink>http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</feedburner:origLink>
</item>
....items....
</channel>
</rss>
All I want is to get the "http://global.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg", and before that check if content:encoded exists..
Thanks.
EDIT:
I've found a sample that I can show and edit the code that tries to handle it..
EDIT2:
I've done it in the ugly way:
text.Replace("content:encoded", "contentt").Replace("xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"","");
and then get the element in the normal way:
MediaContent = feed.Element("contentt").Value
The following code
static void Main(string[] args)
{
var XMLFeed = XDocument.Parse(
#"<rss>
<channel>
....items....
<item>
<title>Pentagon confirms plan to create new spy agency</title>
<link>http://feeds.foxnews.com/~r/foxnews/most-popular/~3/lVUZwCdjVsc/</link>
<category>politics</category>
<dc:creator xmlns:dc='http://purl.org/dc/elements/1.1/' />
<pubDate>Tue, 24 Apr 2012 12:44:51 PDT</pubDate>
<guid isPermaLink='false'>http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</guid>
<content:encoded xmlns:content='http://purl.org/rss/1.0/modules/content/'><![CDATA[|http://global.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg<img src='http://feeds.feedburner.com/~r/foxnews/most-popular/~4/lVUZwCdjVsc' height='1' width='1'/>]]></content:encoded>
<description>The Pentagon confirmed Tuesday that it is carving out a brand new spy agency expected to include several hundred officers focused on intelligence gathering around the world.&amp;#160;</description>
<dc:date xmlns:dc='http://purl.org/dc/elements/1.1/'>2012-04-4T19:44:51Z</dc:date>
<!-- <feedburner:origLink>http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</feedburner:origLink> -->
</item>
....items....
</channel>
</rss>");
XNamespace contentNs = "http://purl.org/rss/1.0/modules/content/";
var feeds = from feed in XMLFeed.Descendants("item")
select new
{
Title = (string)feed.Element("title"),
Link = (string)feed.Element("link"),
pubDate = (string)feed.Element("pubDate"),
Description = (string)feed.Element("description"),
MediaContent = GetMediaContent((string)feed.Element(contentNs + "encoded"))
};
foreach(var item in feeds)
{
Console.WriteLine(item);
}
}
private static string GetMediaContent(string content)
{
int imgStartPos = content.IndexOf("<img");
if(imgStartPos > 0)
{
int startPos = content[0] == '|' ? 1 : 0;
return content.Substring(startPos, imgStartPos - startPos);
}
return string.Empty;
}
results in:
{ Title = Pentagon confirms plan to create new spy agency, Link = http://feeds.f
oxnews.com/~r/foxnews/most-popular/~3/lVUZwCdjVsc/, pubDate = Tue, 24 Apr 2012 1
2:44:51 PDT, Description = The Pentagon confirmed Tuesday that it is carving out
a brand new spy agency expected to include several hundred officers focused on
intelligence gathering around the world. , MediaContent = http://global
.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg }
Press any key to continue . . .
A few points:
You never want to treat Xml as text - in your case you removed the namespace declaration but actually if the namespace was declared inline (i.e. without binding to the prefix) or a different prefix would be defined your code would not work even though semantically both documents would be equivalent
Unless you know what's inside CDATA and how to treat it you always want to treat is as text. If you know it's something else you can treat it differently after parsing - see my elaborate on CDATA below for more details
To avoid NullReferenceExceptions if the element is missing I used explicit conversion operator (string) instead of invoking .Value
the Xml you posted was not a valid xml - there was missing namespace Uri for feedburner prefix
This is no longer related to the problem but may be helpful for some folks so I am leaving it
As far as the contents of the encode element is considered it is inside CDATA section. What's inside CDATA section is not an Xml but plain text. CDATA is usually used to not have to encode '<', '>', '&' characters (without CDATA they would have to be encoded as < > and & to not break the Xml document itself) but the Xml processor treat characters in the CDATA as if they were encoded (or to be more correct in encodes them). The CDATA is convenient if you want to embed html because textually the embedded content looks like the original yet it won't break your xml if the html is not a well-formed Xml. Since the CDATA content is not an Xml but text it is not possible to treat it as Xml. You will probably need to treat is as text and use for instance regular expressions. If you know it is a valid Xml you can load the contents to an XElement again and process it. In your case you have got mixed content so it is not easy to do unless you use a little dirty hack. Everything would be easy if you have just one top level element instead of mixed content. The hack is to add the element to avoid all the hassle. Inside the foreach look you can do something like this:
var mediaContentXml = XElement.Parse("<content>" + (string)item.MediaContent + "</content>");
Console.WriteLine((string)mediaContentXml.Element("img").Attribute("src"));
Again it's not pretty and it is a hack but it will work if the content of the encoded element is valid Xml. The more correct way of doing this is to us XmlReader with ConformanceLevel set to Fragment and recognize all kinds of nodes appropriately to create a corresponding Linq to Xml node.
You should use XNamespace:
XNamespace content = "...";
// later in your code ...
MediaContent = feed.Element(content + "encoded")
See more details here.
(Of course, you the string to be assigned to content is the same as in xmlns:content="...").

How to get chart info from an Excel spreadsheet using Apache POI?

Is it possible to extract chart information from an Office 2007 (xlsx / OpenXML) spreadsheet using Apache POI? I've managed to read in the spreadsheet and even get the part that refers to the chart but not sure how I can retrieve any info from this part e.g. Type of chart, chart data etc.
XSSFWorkbook xwb = new XSSFWorkbook("charts_lines.xlsx");
XSSFSheet sheet = xwb.getSheetAt(0);
I can also iterate through the package parts to retrieve the chart part, but I don't see how I then go on to retrieve any info about the chart?
Note, I'm not interested in creating charts using POI, just read as much chart info as is possible to do...I'm also not saving an xlsx. I simply wish to extract line colours, labels, data, chart type (pie, line, bar etc.)
There isn't a high level representation at the moment, so you'll need to drop down into the xmlbeans level and work with the low level CT* objects.
For Chart Sheets, there's XSSFChartSheet which will give you a CTChartsheet object, which has a little bit of info.
For both XSSFChart and XSSFChartSheet (regular and chart sheets), you'll need to go via the drawings to get the charts. Each sheet with charts on it should have one Drawing, and the charts get linked from the drawing, rather than the sheet itself.
As of r1090442 (so POI 3.8 or newer), there's a method on XSSFDrawing to give you all the XSSFChart objects (which are wrappers around the /charts/chart#.xml part). If you're on a really really old version of POI, use the CTDrawing to get the details of the chart, grab the /charts/chart#.xml part that corresponts, and then have xmlbeans give you the CT objects for it. Either way that'll let you get the titles, types, data ranges etc.
It is a bit fiddly though, so do please consider sending in a patch to POI if you get something good worked out for working with the CTChart objects!
you can read chart data as XML using XSSFDrawing
like
XSSFDrawing drawing = ((XSSFSheet)sheet).createDrawingPatriarch();
System.out.println(drawing.getCTDrawing().toString());
will print whole chart as XMl and also using
drawing.getCharts();
you can add Iterator to it to browse chart
I don't know the exact answer to your question, but the OpenXML SDK 2.0 comes with a DocumentReflector.exe tool that will show you exactly how the chart is defined (including all relationships between the SpreadsheetML and the DrawingML packages). There is some more info on this tool in this article.
Yes, It is possible to read any type of chart using Apache POI. But Before reading any chart information you need to know what XML string you are receiving because this could be different based on the chart type i.e. pie, line, bar, scatter or mixed (a combination of two or more) charts, etc. Therefore you approach will be different for different type of chart.
For a simple bar chart like this:
Your XML will look something like this:
<xml-fragment ...>
<c:title>
<c:tx>
<c:rich>
...
<a:p>
...
<a:r>
...
<a:t>Employee Salary</a:t>
</a:r>
</a:p>
</c:rich>
</c:tx>
...
</c:title>
...
<c:plotArea>
...
<c:barChart>
...
<c:ser>
...
<c:cat>
<c:strRef>
...
<c:strCache>
<c:ptCount val="5"/>
<c:pt idx="0">
<c:v>Tom</c:v>
</c:pt>
<c:pt idx="1">
<c:v>John</c:v>
</c:pt>
<c:pt idx="2">
<c:v>Harry</c:v>
</c:pt>
<c:pt idx="3">
<c:v>Sam</c:v>
</c:pt>
<c:pt idx="4">
<c:v>Richa</c:v>
</c:pt>
</c:strCache>
</c:strRef>
</c:cat>
<c:val>
<c:numRef>
...
<c:numCache>
<c:formatCode>"$"#,##0</c:formatCode>
<c:ptCount val="5"/>
<c:pt idx="0">
<c:v>1000</c:v>
</c:pt>
<c:pt idx="1">
<c:v>700</c:v>
</c:pt>
<c:pt idx="2">
<c:v>300</c:v>
</c:pt>
<c:pt idx="3">
<c:v>900</c:v>
</c:pt>
<c:pt idx="4">
<c:v>800</c:v>
</c:pt>
</c:numCache>
</c:numRef>
</c:val>
...
</c:ser>
...
</c:barChart>
...
</c:plotArea>
...
</xml-fragment>
Now based on the above XML String we can use CT* classes and its various methods to traverse through the whole XML using Apache POI. Let's see how to read Chart Title, Labels(Employee names) and Series(Employee salaries) using POI:
Workbook workbook = new XSSFWorkbook(new File(PATH));
Sheet sheet = workbook.getSheet("GraphSheet");
XSSFSheet xsheet = (XSSFSheet) sheet;
XSSFDrawing drawing = xsheet.getDrawingPatriarch();
if (drawing != null) {
List<XSSFChart> charts = drawing.getCharts();
for (int chartIndex = 0; charts != null && chartIndex < (charts.size()); chartIndex++) {
XSSFChart chart = charts.get(chartIndex);
CTChart chart2 = chart.getCTChart();
CTPlotArea plot = chart2.getPlotArea();
System.out.println("Chart Title :" + chart2.getTitle().getTx().getRich().getPArray(0).getRArray(0).getT());
CTBarSer[] ctScaSerList = plot.getBarChartArray(0).getSerArray();
for (CTBarSer ctLineSer : ctScaSerList) {
CTStrVal[] ctStrVals = ctLineSer.getCat().getStrRef().getStrCache().getPtArray();
for (int i = 0; i < ctStrVals.length; i++) {
System.out.print(ctStrVals[i].getV() + ",");
}
System.out.println();
CTNumVal[] ctXNumVal = ctLineSer.getVal().getNumRef().getNumCache().getPtArray();
for (int i = 0; i < ctXNumVal.length; i++) {
System.out.print(ctXNumVal[i].getV() + ",");
}
}
}
}
Console:
Chart Title :Employee Salary
Tom,John,Harry,Sam,Richa,
1000,700,300,900,800,
Note: Here, the idea is to first read the XML String(because could be different based on your graph type) and then traverse the whole XML accordingly.