i'm a beginner in java and XML , but I have a task to perform and I don't know how to use a recursive function which uses Element.
I made this program.
public class JDOM2
{
private static final String xmlroutes = "C://Users//Thomas//Desktop//routes.xml";
static Element root;
public static void main(String[] args) throws JDOMException, IOException
{
// the SAXBuilder is the easiest way to create the JDOM2 objects.
SAXBuilder jdomBuilder = new SAXBuilder();
// jdomDocument is the JDOM2 Object
Document jdomDocument = jdomBuilder.build(xmlroutes);
root = jdomDocument.getRootElement();
List <Element> location_properties = root.getChildren("LOCATION_PROPERTIES");
Iterator<Element> it = location_properties.iterator();
Element loc = it.next();
rootiteration();
}
public static void rootiteration()
{
int time;
List <Element> location_properties = root.getChildren("LOCATION_PROPERTIES");
Iterator<Element> it = location_properties.iterator();
Element loc = it.next();
if(loc.getAttributeValue("NAME").startsWith("STN")== true)
{
List <Element> segment_properties = loc.getChildren("SEGMENT_PROPERTIES");
Iterator<Element> it2 = segment_properties.iterator();
Element seg = it2.next();
List <Element> next_location = seg.getChildren("NEXT_LOCATION");
for (Element next: next_location)
{
if(next.getAttributeValue("NAME").startsWith("STN")== true)
{
System.out.print("Arrival : " +next.getAttributeValue("NAME"));
int L = Integer.parseInt(next.getAttributeValue("LENGTH"));
int S = Integer.parseInt(next.getAttributeValue("SPEED"));
time = L/S;
System.out.println(" --- Time to go : "+time+" seconds");
}
if(next.getAttributeValue("NAME").startsWith("STN")== false)
{
recursive(); // I think the problem is here but I may have done some other mistakes.
}
}
}
}
public static int recursive(Element parent, int t0, Element child) throws IOException
{
List <Element> location_properties = root.getChildren("LOCATION_PROPERTIES");
Iterator <Element> i = location_properties.iterator();
int t1 = 0;
while (i.hasNext())
{
child = (Element) i.next();
int L = Integer.parseInt(child.getChild("SEGMENT_PROPERTIES").getChild("NEXT_LOCATION").getAttributeValue("LENGTH"));
int S = Integer.parseInt(child.getChild("SEGMENT_PROPERTIES").getChild("NEXT_LOCATION").getAttributeValue("SPEED"));
t1 = L/S;
//t1 = time_between();
if (child.getAttributeValue("NAME").startsWith("STN")== true)
{
System.out.println("From : "+parent+" to "+child+" --- Time to go : "+t1+" seconds");
System.out.println(child.getAttributeValue("NAME"));
System.out.println(parent);
}
if (child.getAttributeValue("NAME").startsWith("X")== true) // child is not STN, recurse
{
recursive(parent, t0 + t1,child);
System.out.println("From : "+parent+" to "+child+" --- Time to go : "+t1+" seconds");
// t0 = t0 + t1;
}
}
return t0;
}
This is supposed to calculate the time between 2 Elements. King of this way :
I need two functions, one which iterates over all root elements, and starts the tree traversal at a starting STN, and a recursive function that traverse the tree until it finds an ending STN.
To have something like that :
Departure Station : STN10
Arrival : X535 --- Time to go : 16 seconds
Arrival : X536 --- Time to go : 2 seconds
Arrival : X537 --- ...
Arrival : STN26 --- Total time to Station : ...
Departure Station : STN11
Arrival : X535 ---
...And so on.
I think you can change the second method as follows and it would work:
public static int recursive(Element root, int t0, Element current) throws IOException
{
List <Element> location_properties = current.getChildren("LOCATION_PROPERTIES");
Iterator <Element> i = location_properties.iterator();
int t1 = 0;
while (i.hasNext())
{
child = (Element) i.next();
int L = Integer.parseInt(child.getChild("SEGMENT_PROPERTIES").getChild("NEXT_LOCATION").getAttributeValue("LENGTH"));
int S = Integer.parseInt(child.getChild("SEGMENT_PROPERTIES").getChild("NEXT_LOCATION").getAttributeValue("SPEED"));
t1 = L/S;
//t1 = time_between();
if (child.getAttributeValue("NAME").startsWith("STN")== true)
{
System.out.println("From : "+root+" to "+child+" --- Time to go : "+t1+" seconds");
System.out.println(child.getAttributeValue("NAME"));
}
if (child.getAttributeValue("NAME").startsWith("X")== true) // child is not STN, recurse
{
recursive(root, t0 + t1, child);
}
}
return t0;
}
Everytime a non-STN element is encountered the child element will be passed to the recursive method as the current element.
You will have to call this method using the root element as the root parameter and the same element as the current parameter. i.e., recursive(root, 0, root).
Please note that I could not test this as the xml file is not accessible to me. Hope this helps.
For those who can be interested, I used this function to re-use the string "next.getAttributeValue("NAME")" as an element.
public static Element getElembyName(final String name){
List <Element> location_properties = root.getChildren("LOCATION_PROPERTIES");
for (Element loc : location_properties)
{
if(loc.getAttributeValue("NAME").equals(name))
return loc;
}
return null;
}
Related
Is there a way to convert a string given in ISO 8601 period format to a format readable by humans and also translated to specified language?
Example:
P1W --en--> 1 Week
P2W --en--> 2 Weeks
P1W --pl--> 1 Tydzień
P2W --pl--> 2 Tygodnie
I am looking for an already implemented solution, without the necessity of defining periods translations.
The Unicode Common Locale Data Repository, commonly known as the CLDR, is an authoritative repository for localized information of all kinds, including translations.
Since Java 9, Java SE has used the CLDR for a lot of (if not all) localization functionality. But I am not aware of any localized formatting of java.time.Period instances using CLDR data files.
The CLDR has its own Java tools, but I experimented with the compiled .jar for hours and could not figure out how to use it. I couldn’t find documentation beyond the (very short) command line help. If it has an API for formatting periods, I would definitely favor using that.
But the CLDR data files are still the best place to get this information. (They can also be cloned from https://github.com/unicode-org/cldr) So, with that in mind, I wrote a (rather long) class to format Period instances using CLDR data files.
There are a few steps involved:
First, code must determine the language cardinality for a particular number. In English, there are only two choices: singular and plural. Other languages can be more complex. The common/supplemental/plurals.xml file in the CLDR contains all of this data for all locales; its format is documented on unicode.org.
Most localized data is in the common/main directory of the CLDR, as .xml files named by locale. The elements related to periods are in <ldml> → <units> → <unitLength type="long"> → <unit type="duration-week">, as well as type="duration-year", type="duration-month", and type="duration-day". Within the unit element are <unitPattern> elements, each with a count attribute referencing the cardinality described above.
Finally, the same locale-specific file in common/main contains <listPattern> elements which describe how to format a list of items, including <listPattern type="unit"> for assembling a list of period parts. The use of this data is described here.
Note that Period.parse accepts the ISO 8601 format, including weeks, but the Period class itself does not keep track of weeks, so if output with weeks is desired, code must divide the Period’s days by 7.
Here is what I came up with. The parsing is not robust and makes a lot of assumptions about correct CLDR data. There are probably ways to speed up the reading of the XML files, such as caching recently used ones, so consider this a proof of concept:
public class PeriodFormatter {
public enum Count {
EXACTLY0("0"),
EXACTLY1("1"),
ZERO,
ONE,
TWO,
FEW,
MANY,
OTHER;
private final String attributeValue;
Count() {
this.attributeValue = name().toLowerCase(Locale.US);
}
Count(String attributeValue) {
this.attributeValue = attributeValue;
}
String attributeValue() {
return attributeValue;
}
static Count forAttributeValue(String attrValue) {
for (Count count : values()) {
if (count.attributeValue.equals(attrValue)) {
return count;
}
}
throw new IllegalArgumentException(
"No Count with attribute value \"" + attrValue + "\"");
}
}
private static class Range {
final long start;
final long end;
Range(long value) {
this(value, value);
}
Range(long start,
long end) {
this.start = start;
this.end = end;
}
boolean contains(long value) {
return value >= start && value <= end;
}
boolean contains(double value) {
return value >= start && value <= end;
}
}
private enum Operand {
ABSOLUTE_VALUE("n"),
INTEGER_PART("i"),
FRACTIONAL_PRECISION("v"),
FRACTIONAL_PRECISION_TRIMMED("w"),
FRACTIONAL_PART("f"),
FRACTIONAL_PART_TRIMMED("t"),
EXPONENT_PART("c", "e");
final String[] tokens;
private Operand(String... tokens) {
this.tokens = tokens;
}
static Operand forToken(String token) {
for (Operand op : values()) {
if (Arrays.asList(op.tokens).contains(token)) {
return op;
}
}
throw new IllegalArgumentException(
"No Operand for token \"" + token + "\"");
}
}
private static class Expression {
final Operand operand;
final Long modValue;
Expression(Operand operand,
Long modValue) {
this.operand = operand;
this.modValue = modValue;
}
double evaluate(BigDecimal value) {
switch (operand) {
case ABSOLUTE_VALUE:
return Math.abs(value.doubleValue());
case INTEGER_PART:
return value.longValue();
case FRACTIONAL_PRECISION:
return Math.max(value.scale(), 0);
case FRACTIONAL_PRECISION_TRIMMED:
return Math.max(value.stripTrailingZeros().scale(), 0);
case FRACTIONAL_PART:
BigDecimal frac = value.remainder(BigDecimal.ONE);
frac = frac.movePointRight(Math.max(0, frac.scale()));
return frac.doubleValue();
case FRACTIONAL_PART_TRIMMED:
BigDecimal trimmed =
value.stripTrailingZeros().remainder(BigDecimal.ONE);
trimmed = trimmed.movePointRight(
Math.max(0, trimmed.scale()));
return trimmed.longValue();
case EXPONENT_PART:
String expStr = String.format("%e", value);
return Long.parseLong(
expStr.substring(expStr.indexOf('e') + 1));
default:
break;
}
throw new RuntimeException("Unknown operand " + operand);
}
}
private static abstract class Relation {
boolean negated;
Expression expr;
abstract boolean matches(BigDecimal value);
final boolean matchIfIntegral(BigDecimal value,
LongPredicate test) {
double evaluatedValue = expr.evaluate(value);
long rounded = Math.round(evaluatedValue);
return Math.abs(evaluatedValue - rounded) < 0.000001
&& test.test(rounded);
}
}
private static class IsRelation
extends Relation {
long value;
#Override
boolean matches(BigDecimal value) {
return matchIfIntegral(value, n -> n == this.value);
}
}
private static class InRelation
extends Relation {
final List<Range> ranges = new ArrayList<>();
#Override
boolean matches(BigDecimal value) {
return ranges.stream().anyMatch(
range -> matchIfIntegral(value, n -> range.contains(n)));
}
}
private static class WithinRelation
extends Relation {
final List<Range> ranges = new ArrayList<>();
#Override
boolean matches(BigDecimal value) {
return ranges.stream().anyMatch(r -> r.contains(value.longValue()));
}
}
private static class Condition {
final List<Relation> relations = new ArrayList<>();
boolean matches(BigDecimal value) {
return relations.stream().allMatch(r -> r.matches(value));
}
}
private static class AndConditionSequence {
final List<Condition> conditions = new ArrayList<>();
boolean matches(BigDecimal value) {
return conditions.stream().allMatch(c -> c.matches(value));
}
}
private static class PluralRule {
final Count count;
final List<AndConditionSequence> conditions = new ArrayList<>();
PluralRule(String countSpec,
String ruleSpec) {
this.count = Count.forAttributeValue(countSpec);
Scanner scanner = new Scanner(ruleSpec);
AndConditionSequence andSequence = new AndConditionSequence();
Condition condition = new Condition();
andSequence.conditions.add(condition);
this.conditions.add(andSequence);
while (true) {
String token = scanner.findWithinHorizon("\\S", 0);
if (token.equals("#")) {
// Ignore samples.
break;
}
Operand operand = Operand.forToken(token);
Long modValue = null;
token = scanner.findWithinHorizon(
"mod|%|is|in|within|!?=|not", 0);
if (token.equals("mod") || token.equals("%")) {
modValue = Long.valueOf(
scanner.findWithinHorizon("\\d+", 0));
token = scanner.findWithinHorizon(
"is|in|within|!?=|not", 0);
}
Relation relation;
boolean negated = false;
if (token.equals("not")) {
token = scanner.findWithinHorizon("in|within", 0);
if (token.equals("within")) {
WithinRelation within = new WithinRelation();
relation = within;
within.negated = true;
parseRanges(within.ranges, scanner);
} else {
InRelation in = new InRelation();
relation = in;
in.negated = true;
parseRanges(in.ranges, scanner);
}
relation.negated = true;
} else if (token.equals("is")) {
IsRelation is = new IsRelation();
relation = is;
token = scanner.findWithinHorizon("not|\\d+", 0);
if (token.equals("not")) {
is.negated = true;
token = scanner.findWithinHorizon("\\d+", 0);
}
is.value = Long.valueOf(token);
} else if (token.endsWith("=")) {
InRelation in = new InRelation();
relation = in;
in.negated = token.startsWith("!");
parseRanges(in.ranges, scanner);
} else {
throw new RuntimeException(
"Unexpected token '" + token + "'");
}
relation.expr = new Expression(operand, modValue);
condition.relations.add(relation);
if (!scanner.hasNext("and|or")) {
break;
}
token = scanner.next();
if (token.equals("and")) {
condition = new Condition();
andSequence.conditions.add(condition);
} else {
andSequence = new AndConditionSequence();
this.conditions.add(andSequence);
}
}
}
static void parseRanges(Collection<Range> ranges,
Scanner scanner) {
boolean first = true;
while (true) {
if (!first) {
if (!scanner.hasNext(",.*")) {
break;
}
scanner.findWithinHorizon(",", 0);
}
String token =
scanner.findWithinHorizon("\\d+(?:\\.\\.\\d+)?", 0);
int period = token.indexOf('.');
if (period > 0) {
long start = Long.parseLong(token.substring(0, period));
long end = Long.parseLong(token.substring(period + 2));
ranges.add(new Range(start, end));
} else {
long value = Long.parseLong(token);
ranges.add(new Range(value));
}
first = false;
}
}
boolean matches(BigDecimal value) {
return conditions.stream().anyMatch(c -> c.matches(value));
}
}
private static final Map<Locale, List<PluralRule>> pluralRules =
new HashMap<>();
private static final Map<Locale, Path> dataFiles = new HashMap<>();
private static final Path cldrDir;
static {
String dir = System.getProperty("cldr");
if (dir == null) {
throw new RuntimeException(
"\"cldr\" system property must be set to root directory"
+ " of CLDR data. That data can be downloaded from"
+ "https://cldr.unicode.org/index/downloads or"
+ "https://github.com/unicode-org/cldr .");
}
cldrDir = Paths.get(dir);
}
private final XPath xpath;
public PeriodFormatter() {
this.xpath = XPathFactory.newInstance().newXPath();
}
private static InputSource createSource(Path path) {
return new InputSource(path.toUri().toASCIIString());
}
private Count countFor(BigDecimal amount,
Locale locale) {
synchronized (pluralRules) {
if (pluralRules.isEmpty()) {
Path pluralsFile = cldrDir.resolve(
Paths.get("common", "supplemental", "plurals.xml"));
NodeList rulesElements;
try {
rulesElements = (NodeList) xpath.evaluate(
"//plurals[#type='cardinal']/pluralRules",
createSource(pluralsFile),
XPathConstants.NODESET);
} catch (XPathException e) {
throw new RuntimeException(e);
}
int count = rulesElements.getLength();
for (int i = 0; i < count; i++) {
Element rulesElement = (Element) rulesElements.item(i);
String[] localeNames =
rulesElement.getAttribute("locales").split("\\s+");
NodeList ruleElements =
rulesElement.getElementsByTagName("pluralRule");
int ruleCount = ruleElements.getLength();
List<PluralRule> ruleList = new ArrayList<>(ruleCount);
for (int j = 0; j < ruleCount; j++) {
Element ruleElement = (Element) ruleElements.item(j);
ruleList.add(new PluralRule(
ruleElement.getAttribute("count"),
ruleElement.getTextContent()));
}
for (String localeName : localeNames) {
localeName = localeName.replace('_', '-');
pluralRules.put(
Locale.forLanguageTag(localeName),
ruleList);
}
}
}
}
Locale availableLocale = Locale.lookup(
Locale.LanguageRange.parse(locale.toLanguageTag()),
pluralRules.keySet());
if (availableLocale == null) {
availableLocale = Locale.ROOT;
}
List<PluralRule> rulesOfLocale = pluralRules.get(availableLocale);
for (PluralRule rule : rulesOfLocale) {
if (rule.matches(amount)) {
return rule.count;
}
}
throw new IllegalArgumentException("No plural rule matches " + amount);
}
private static List<Locale> listWithFallbacks(Locale locale) {
Collection<Locale> locales = new LinkedHashSet<>();
locales.add(locale);
Locale.Builder builder = new Locale.Builder();
builder.setLanguageTag(locale.toLanguageTag());
locales.add(builder.setVariant(null).build());
locales.add(builder.setRegion(null).build());
locales.add(builder.setScript(null).build());
locales.add(Locale.ROOT);
return new ArrayList<>(locales);
}
private Iterable<Path> dataFilesFor(Locale locale) {
synchronized (dataFiles) {
if (dataFiles.isEmpty()) {
Path dataFileDir = cldrDir.resolve(Paths.get("common", "main"));
try (DirectoryStream<Path> dir =
Files.newDirectoryStream(dataFileDir, "*.xml")) {
for (Path dataFile : dir) {
InputSource source = createSource(dataFile);
NodeList identityElements = (NodeList)
xpath.evaluate("/ldml/identity", source,
XPathConstants.NODESET);
Element identity = (Element) identityElements.item(0);
String lang =
xpath.evaluate("language/#type", identity);
String script =
xpath.evaluate("script/#type", identity);
String region =
xpath.evaluate("territory/#type", identity);
String variant =
xpath.evaluate("variant/#type", identity);
Locale dataFileLocale;
if (lang.equals("root")) {
dataFileLocale = Locale.ROOT;
} else {
Locale.Builder builder = new Locale.Builder();
builder.setLanguage(lang);
builder.setScript(script);
builder.setRegion(region);
builder.setVariant(variant);
dataFileLocale = builder.build();
}
dataFiles.put(dataFileLocale, dataFile);
}
} catch (IOException | XPathException e) {
throw new RuntimeException(e);
}
}
}
Collection<Locale> locales = listWithFallbacks(locale);
Collection<Path> dataFilesForLocale = new ArrayList<>();
for (Locale localeToCheck : locales) {
Path dataFile = dataFiles.get(localeToCheck);
if (dataFile != null) {
dataFilesForLocale.add(dataFile);
}
}
return dataFilesForLocale;
}
private Optional<Element> locateElement(Object source,
String path) {
try {
Element element = null;
while (true) {
NodeList elements;
if (source instanceof InputSource) {
elements = (NodeList) xpath.evaluate(path,
(InputSource) source, XPathConstants.NODESET);
} else {
elements = (NodeList) xpath.evaluate(path,
source, XPathConstants.NODESET);
}
if (elements.getLength() < 1) {
break;
}
element = (Element) elements.item(0);
NodeList list = (NodeList) xpath.evaluate("alias", element,
XPathConstants.NODESET);
if (list.getLength() == 0) {
// No more aliases to follow, so we've found our target.
break;
}
Element alias = (Element) list.item(0);
path = alias.getAttribute("path");
source = element;
}
return Optional.ofNullable(element);
} catch (XPathException e) {
throw new RuntimeException(e);
}
}
private Optional<String> readElement(Iterable<? extends Path> dataFiles,
String... paths)
throws XPathException {
Optional<Element> element = Optional.empty();
for (Path dataFile : dataFiles) {
Object source = createSource(dataFile);
element = Optional.empty();
for (String path : paths) {
element = locateElement(source, path);
if (!element.isPresent()) {
break;
}
source = element.get();
}
if (element.isPresent()) {
break;
}
}
return element.map(Element::getTextContent);
}
private String format(ChronoUnit units,
BigDecimal amount,
Locale locale) {
String type = null;
switch (units) {
case YEARS:
type = "duration-year";
break;
case MONTHS:
type = "duration-month";
break;
case WEEKS:
type = "duration-week";
break;
case DAYS:
type = "duration-day";
break;
default:
throw new IllegalArgumentException(
"Valid units are YEARS, MONTHS, WEEKS, and DAYS.");
}
Count count = countFor(amount, locale);
try {
Optional<String> formatPattern = readElement(dataFilesFor(locale),
"/ldml/units" +
"/unitLength[#type='long']" +
"/unit[#type='" + type + "']",
"unitPattern[#count='" + count.attributeValue() + "']");
if (formatPattern.isPresent()) {
String patternStr = formatPattern.get();
if (!patternStr.isEmpty()) {
MessageFormat format =
new MessageFormat(patternStr, locale);
return format.format(new Object[] { amount });
}
}
} catch (XPathException e) {
throw new RuntimeException(e);
}
throw new IllegalArgumentException(
"Could not find pattern for units " + units +
", amount " + amount + ", locale " + locale.toLanguageTag());
}
public String format(Period period,
Locale locale) {
return format(period, false, locale);
}
public String format(Period period,
boolean includeWeeks,
Locale locale) {
int years = period.getYears();
int months = period.getMonths();
int days = period.getDays();
List<String> parts = new ArrayList<>(3);
if (years != 0) {
BigDecimal value = BigDecimal.valueOf(years);
String yearStr = format(ChronoUnit.YEARS, value, locale);
parts.add(yearStr);
}
if (months != 0) {
BigDecimal value = BigDecimal.valueOf(months);
String monthStr = format(ChronoUnit.MONTHS, value, locale);
parts.add(monthStr);
}
if (includeWeeks) {
int weeks = days / 7;
if (weeks != 0) {
days %= 7;
BigDecimal value = BigDecimal.valueOf(weeks);
String weekStr = format(ChronoUnit.WEEKS, value, locale);
parts.add(weekStr);
}
}
if (days != 0) {
BigDecimal value = BigDecimal.valueOf(days);
String dayStr = format(ChronoUnit.DAYS, value, locale);
parts.add(dayStr);
}
return formatList(parts, locale);
}
private String formatList(List<?> parts,
Locale locale) {
if (parts.isEmpty()) {
return "";
}
int size = parts.size();
if (size == 1) {
return String.valueOf(parts.get(0));
}
Map<String, String> patternsByType = new HashMap<>();
for (Path dataFile : dataFilesFor(locale)) {
Object source = createSource(dataFile);
Optional<Element> listPatterns =
locateElement(source, "/ldml/listPatterns");
if (!listPatterns.isPresent()) {
continue;
}
Optional<Element> listPattern =
locateElement(listPatterns.get(), "listPattern[#type='unit']");
if (!listPattern.isPresent()) {
continue;
}
NodeList partList =
listPattern.get().getElementsByTagName("listPatternPart");
int count = partList.getLength();
for (int i = 0; i < count; i++) {
Element part = (Element) partList.item(i);
String type = part.getAttribute("type");
String pattern = part.getTextContent();
patternsByType.putIfAbsent(type, pattern);
}
}
if (size == 2 || size == 3) {
String pattern = patternsByType.get(String.valueOf(size));
if (pattern != null) {
MessageFormat format =new MessageFormat(pattern, locale);
return format.format(parts.toArray());
}
}
MessageFormat startFormat = new MessageFormat(
patternsByType.get("start"), locale);
MessageFormat middleFormat = new MessageFormat(
patternsByType.get("middle"), locale);
MessageFormat endFormat = new MessageFormat(
patternsByType.get("end"), locale);
String text = endFormat.format(
new Object[] { parts.get(size - 2), parts.get(size - 1) });
int index = size - 2;
while (--index > 0) {
text = middleFormat.format(new Object[] { parts.get(index), text });
}
text = startFormat.format(new Object[] { parts.get(index), text });
return text;
}
public static void main(String[] args) {
String localeStr = System.getProperty("locale");
Locale locale = localeStr != null ?
Locale.forLanguageTag(localeStr) : Locale.getDefault();
boolean showWeeks = Boolean.getBoolean("weeks");
PeriodFormatter formatter = new PeriodFormatter();
for (String arg : args) {
Period period = Period.parse(arg);
String s = formatter.format(period, showWeeks, locale);
System.out.println(arg + " => " + s);
}
}
}
Sorry twice it seems, but i'd leave this post here, that problem is a terrible fright about calender display name fields, back in 2010 i spent a couple of days looking for the hr,min,sec displayneames until i got info from Sun Microsystems forum there were no names for some. The API doc info almost says that, just not clearly. Niether does it say anything clearly for java.time.temporal.TemporalField and java.time.temporal.ChronoField
and its method getDisplayName(Locale locale)
Sorry(deleted other answer), I thought you meant "time" itself, you meant "time UNITS" that are part of java TemporalUnit of the Duration is a Temporal with TemporalUnit's AND do have "name retrieval methods" but translated, no.
However, java.util.Calendar also has "time units" AND can be instantiated with Locale and should have class fields and methods that will return "time unit" foreign language names
This is a test printer class for a field that does have a display name. The commented out code prints "null" returned by getDisplayName()
// CalendarTest.java
public class CalendarTest{
int[] ipt = {java.util.Calendar.DAY_OF_WEEK,java.util.Calendar.MONTH,java.util.Calendar.ERA,java.util.Calendar.AM_PM};
public CalendarTest(){
//java.time.LocalDateTime tm = java.time.LocalDateTime.now(); +java.util.Calendar.HOUR DAY_OF_WEEK
for(int sd=0;sd<ipt.length;sd++){
pr(ipt[sd],"fr");
}
for(int sd1=0;sd1<ipt.length;sd1++){
pr(ipt[sd1],"zh");
}
for(int sd2=0;sd2<ipt.length;sd2++){
pr(ipt[sd2],"ar");
}
/*
//java.util.Date dt = cal.getTime();
System.out.println(""+cal.get(java.util.Calendar.HOUR));
String fieldname = cal.getDisplayName(java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.SHORT, new java.util.Locale("en"));
System.out.println(fieldname);
fieldname = cal.getDisplayName(java.util.Calendar.HOUR_OF_DAY, java.util.Calendar.LONG, new java.util.Locale("en"));
System.out.println(fieldname);
*/
}//enconstr
public void pr(int fieldint,String loc){
java.util.Calendar cal = java.util.Calendar.getInstance(new java.util.Locale(loc));
java.util.Map<String,Integer> mp = cal.getDisplayNames(fieldint , java.util.Calendar.ALL_STYLES, new java.util.Locale(loc));
if(mp.isEmpty()==true){
System.out.println("Is Empty");
}else{
System.out.println("Contains");
}
java.util.Set<String> st = mp.keySet();
Object[] sta = st.toArray();
for(int fs=0;fs<sta.length;fs++){
System.out.println("A VALUE : "+sta[fs]);
}
}//enmeth
public static void main(String[] args){
new CalendarTest();
}//enmain
}//enclss
/* prints Special field values and in Locale but not field names
bash-5.1$ java CalendarTest
Contains
A VALUE : dimanche
A VALUE : mercredi
A VALUE : vendredi
A VALUE : samedi
A VALUE : jeudi
A VALUE : lundi
A VALUE : mardi
A VALUE : dim.
A VALUE : jeu.
A VALUE : lun.
A VALUE : mar.
A VALUE : mer.
A VALUE : sam.
A VALUE : ven.
Contains
A VALUE : septembre
A VALUE : décembre
A VALUE : novembre
A VALUE : février
A VALUE : janvier
A VALUE : juillet
A VALUE : octobre
A VALUE : avril
A VALUE : févr.
A VALUE : janv.
A VALUE : juil.
A VALUE : sept.
A VALUE : août
A VALUE : avr.
A VALUE : déc.
A VALUE : juin
A VALUE : mars
A VALUE : nov.
A VALUE : oct.
A VALUE : mai
Contains
A VALUE : ap. J.-C.
A VALUE : av. J.-C.
A VALUE : BC
A VALUE : A
A VALUE : B
Contains
A VALUE : AM
A VALUE : PM
A VALUE : a
A VALUE : p
Contains
A VALUE : 星期一
A VALUE : 星期三
A VALUE : 星期二
A VALUE : 星期五
A VALUE : 星期六
A VALUE : 星期四
A VALUE : 星期日
A VALUE : 一
A VALUE : 三
A VALUE : 二
A VALUE : 五
A VALUE : 六
A VALUE : 四
A VALUE : 日
Contains
A VALUE : 10月
A VALUE : 11月
A VALUE : 12月
A VALUE : 十一月
A VALUE : 十二月
A VALUE : 10
A VALUE : 11
A VALUE : 12
A VALUE : 1月
A VALUE : 2月
A VALUE : 3月
A VALUE : 4月
A VALUE : 5月
A VALUE : 6月
A VALUE : 7月
A VALUE : 8月
A VALUE : 9月
A VALUE : 一月
A VALUE : 七月
A VALUE : 三月
A VALUE : 九月
A VALUE : 二月
A VALUE : 五月
A VALUE : 八月
A VALUE : 六月
A VALUE : 十月
A VALUE : 四月
A VALUE : 1
A VALUE : 2
A VALUE : 3
A VALUE : 4
A VALUE : 5
A VALUE : 6
A VALUE : 7
A VALUE : 8
A VALUE : 9
Contains
A VALUE : 公元前
A VALUE : AD
A VALUE : BC
A VALUE : 公元
A VALUE : A
A VALUE : B
Contains
A VALUE : 上午
A VALUE : 下午
A VALUE : a
A VALUE : p
Contains
A VALUE : الأربعاء
A VALUE : الثلاثاء
A VALUE : الاثنين
A VALUE : الجمعة
A VALUE : الخميس
A VALUE : الأحد
A VALUE : السبت
A VALUE : ث
A VALUE : ج
A VALUE : ح
A VALUE : خ
A VALUE : ر
A VALUE : س
A VALUE : ن
Contains
A VALUE : أكتوبر
A VALUE : ديسمبر
A VALUE : سبتمبر
A VALUE : فبراير
A VALUE : نوفمبر
A VALUE : أبريل
A VALUE : أغسطس
A VALUE : يناير
A VALUE : يوليو
A VALUE : يونيو
A VALUE : مارس
A VALUE : مايو
A VALUE : أبر
A VALUE : أغس
A VALUE : أكت
A VALUE : ديس
A VALUE : سبت
A VALUE : فبر
A VALUE : مار
A VALUE : ماي
A VALUE : نوف
A VALUE : ينا
A VALUE : يول
A VALUE : يون
A VALUE : أ
A VALUE : ب
A VALUE : د
A VALUE : س
A VALUE : غ
A VALUE : ف
A VALUE : ك
A VALUE : ل
A VALUE : م
A VALUE : ن
A VALUE : و
A VALUE : ي
Contains
A VALUE : ق.م
A VALUE : A
A VALUE : B
A VALUE : م
Contains
A VALUE : a
A VALUE : p
A VALUE : ص
A VALUE : م
bash-5.1$
*/
The below code does not operate (as OleV.V. said) because some fields do not get a SHORT or LONG display name.
java.util.Calendar cal = java.util.Calendar.getInstance( java.util.TimeZone.getTimeZone("Asia/Shanghai") , java.util.Locale.CHINA);
String hourof = cal.getDisplayName(java.util.Calendar.HOUR , java.util.Calendar.LONG , java.util.Locale.CHINA);
Displaying it in html use attribute lang="zh" in the text rendering element tag e.g. div , input , td
UTF-8 is the normal charset to use bound to a locale although for Chinese it may be UTF-16
Take a look at the "field summary" in the API docs for java.util.Calendar.
Week, appears to be a problem but int SHORT could display simply "week" perhaps.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have a flat file directory structure stored in a csv file which contains
id; parentId; name; type; size; classification; checksum;
1;3;file1;file;10;Secret;42;
2; ;folder2;directory; ; ; ;
3;11;folder3;directory; ; ; ;
4;2;file4;file;40;Secret;42;
5;3;file5;file;50;Public;42;
6;3;file6;file;60;Secret;42;
7;3;file7;file;70;Public;42;
8;10;file8;file;80;Secret;42;
9;10;file9;file;90;Top secret;42;
10;11;folder10;directory; ; ; ;
11;2;folder11;directory; ; ; ;
we need to arrange the structure as tree hierarchy by using id and parent id. I am able to do it manually where
it showed in the figure. But when it comes to coding i am not able to find exact solution using correct data structure.
the output should be in the form of root folder to base folder or files when printing the folder it should print the
size of the files and folders in that folder. An appropriate java or python solution will be helpful
name = folder2, type = Directory, size = 400
name = file4, type = File, size = 40, classification = Secret, checksum = 42
name = folder11, type = Directory, size = 360
name = folder10, type = Directory, size = 170
name = file8, type = File, size = 80, classification = Secret, checksum = 42
name = file9, type = File, size = 90, classification = Top secret, checksum = 42
name = folder3, type = Directory, size = 190
name = file1, type = File, size = 10, classification = Secret, checksum = 42
name = file5, type = File, size = 50, classification = Public, checksum = 42
name = file6, type = File, size = 60, classification = Secret, checksum = 42
name = file7, type = File, size = 70, classification = Public, checksum = 42
Here is a very basic Java implementation.
HashMap<String, Set<String>> nodes = new HashMap<>();
File file = new File("E:/test.txt");
try (Stream<String> stream = Files.lines(file.toPath())) {
stream.forEach((line) -> {
String parts[] = line.split(";");
nodes.putIfAbsent(parts[0], new HashSet<>());
nodes.putIfAbsent(parts[1], new HashSet<>());
nodes.get(parts[1]).add(parts[0]);
});
} catch (Exception e) {
e.printStackTrace();
}
The above code maps children files to their parents. This is a lazy method of implementing a tree wherein you know about all of the nodes and their children, which is all information presented in the flat file directory structure. It streams the file line by line; at each line it takes the node id and parent id, creates nodes for either of them if they don't exist before adding the node id to the parent id children set.
The node HashMap looks like this at this stage:
{ =[2], 11=[3, 10], 1=[], 2=[11, 4], 3=[1, 5, 6, 7], 4=[], 5=[], 6=[], 7=[], 8=[], 9=[], 10=[8, 9]}
If you are happy with treating the " " String as the root, you can begin recursively traversing through the list by retrieving the root nodes.get(" ");, otherwise you will need to define how you retrieve the root node.
One potential way of adopting this approach while maintaining the information is to treat each File as a Node.
public static void main (String args[]) {
HashMap<Node, Set<Node>> nodes = new HashMap<>();
File file = new File("E:/test.txt");
try (Stream<String> stream = Files.lines(file.toPath())) {
stream.forEach((line) -> {
String parts[] = line.split(";");
Node node = new Node(parts);
Node parent = new Node(parts[1]);
nodes.putIfAbsent(parent, new HashSet<>());
nodes.putIfAbsent(node, new HashSet<>());
nodes.get(parent).add(node);
});
} catch (Exception e) {
e.printStackTrace();
}
calculateSize(nodes, new Node(" "));
traverse(nodes, new Node(" "));
}
public static void traverse(HashMap<Node, Set<Node>> nodes, Node root) {
System.out.println(root);
for (Node child : nodes.get(root)) {
traverse(nodes, child);
}
}
public static int calculateSize(HashMap<Node, Set<Node>> nodes, Node root) {
int size = root.getSize();
for (Node child : nodes.get(root)) {
size += calculateSize(nodes, child);
}
root.setSize(size);
return size;
}
public static class Node {
private String id = " ";
private String type= " ";
private String name = " ";
private int size = 0;
private String classification = " ";
private int checksum = 0;
public Node (String[] parts) {
this.id = parts[0];
this.name = parts[2];
this.type = parts[3];
this.classification = parts[5];
if (this.type.equals("file")) {
this.size = Integer.parseInt(parts[4]);
this.checksum = Integer.valueOf(parts[6]);
}
}
public Node (String id) {
this.id = id;
}
#Override
public String toString() {
if (name.equals(" ")) return "Root";
String toString = (name.equals(" ")) ? "" : String.format("name = %s", name);
toString += (type.equals(" ")) ? "" : String.format(", type = %s", type);
toString += String.format(", size = %d", size);
toString += (classification.equals(" ")) ? "" : String.format(", classification = %s", classification);
toString += String.format(", checksum = %d", checksum);
return toString;
}
#Override
public boolean equals(Object o) {
if (o instanceof Node) {
return ((Node) o).id.equals(this.id);
} else if (o instanceof String) {
return o.equals(this.id);
}
return false;
}
#Override
public int hashCode() {
return this.id.hashCode();
}
public int getSize() { return size; }
public void setSize(int size) { this.size = size; }
}
The recursive search allows you to traverse through the nodes and print them to console. Note I've overriden the equals, hashCode and toString methods. The equals and hashCode allow you to avoid duplicates and ensure node association is retained.
If you're wanting to sum the files up, you can, as I have suggested, use recursion to calculate the sum for a specific directory and all it's children.
Your question is extremely unclear as to what you want. Please be more clear next time.
As a side note: You're diagram is incorrect. 7 is only a sub-directory of 3, not 10.
You could make 2 classes File and Folder where you can override the __str__() method in those classes to what you need.
I’m developing a companion bot for dementia suffers able to record, store and integrate memories into conversation. The bot calls an xml. file for conversations which can detect contexts passing an argument via baseContext.xml to call a topic.class and dynamically reload new xml data parser and bot while Main.class continues other tasks.
However, I can’t decide if trying to reload the parser/bot into JVM is feasible or whether pausing the class threads and calling a new class/es would be the best solution, or another solution is available. Ideally I’d like to pass the new xml data into the JVM while the other classes persist.
Any help much appreciated.
Main Class (calls the bot, camera, scheduler, text history etc)
public class Main extends javax.swing.JFrame {
private static Bot bot;
public BlockingQueue<String> queue;
public Main() {
initComponents();
//get the parser going
DataParser dp = new DataParser();
//make new bot with level 0 as default and given data parser
bot = new Bot("0", dp);
//dispaly the default message
txtHistory.setText("Bot: " + bot.getMessage());
}
public Main(BlockingQueue<String>queue) {
this.queue = queue;
}
// display bot response in the text area
private static final String VOICENAME="kevin16";
private static void addBotText(String message) {
txtHistory.setText(txtHistory.getText() + "\nBot: " + message);
//turn the bot response to sound
Voice voice;
VoiceManager vm= VoiceManager.getInstance();
voice=vm.getVoice(VOICENAME);
voice.allocate();
try{
voice.speak(bot.getMessage());
}catch(Exception e){
}
voice.deallocate();
}
public static void listen (String speech) {
txtHistory.setText(txtHistory.getText() + "\nYou: " + speech + "\n");
//send the input to the bot and get bot response
The Data parser class deals with the xml loading into DOM
package bot;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class DataParser {
private Document dom;
private HashMap<String, State> states = new HashMap<String, State>();
private ArrayList<String> invalidMessages = new ArrayList();
private int invalidMessageIndex = 0;
public int stateCounter = 1000;
public String fileSource;
// default constructor
public DataParser() {
// Load the XML file and parse it
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//get the filepath of source
String fileSource = Context.getSource();
DocumentBuilder db = dbf.newDocumentBuilder();
//parse using builder to get DOM representation of the XML file
dom = db.parse(fileSource);
// Load configuration and states from the XML file
loadConfiguration();
loadStates();
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (SAXException se) {
se.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
// Load states from XML file
private void loadStates() {
// get document element object
Element docEle = dom.getDocumentElement();
// get all State node names
NodeList nl = docEle.getElementsByTagName("State");
// if node is not null and has children
if (nl != null && nl.getLength() > 0) {
// loop through all children
for (int i = 0; i < nl.getLength(); i++) {
// get state element
Element el = (Element) nl.item(i);
// get state id
String id = el.getAttribute("id");
// get all state messages
ArrayList messages = new ArrayList();
NodeList messagesNodeList = el.getElementsByTagName("message");
// if messages node is not null and has children
if (messagesNodeList != null && messagesNodeList.getLength() > 0) {
// loop through all children
for (int j = 0; j < messagesNodeList.getLength(); j++) {
// get current message element
Element elmsg = (Element) messagesNodeList.item(j);
// append message node value to the messages list
messages.add(elmsg.getFirstChild().getNodeValue());
}
}
// get keywords in the current state
ArrayList keywords = getKeywords(el);
// construct a new State object
State state = new State(id, messages, keywords);
stateCounter ++;
// add the state to the states hashmap
states.put(id, state);
}
}
}
// get state object by id
public State getState(String id) {
return states.get(id);
}
// create a new state
public void addState(State state){
states.put(state.getId(), state);
stateCounter++;
}
// get all keywords in an State tag
public ArrayList getKeywords(Element ele) {
// construct keywords arraylist
ArrayList keywords = new ArrayList();
// get all nodes by keyword tag name
NodeList nl = ele.getElementsByTagName("keyword");
// if the tag is not null and has children
if (nl != null && nl.getLength() > 0) {
// loop through all the children
for (int i = 0; i < nl.getLength(); i++) {
//get the keyword element
Element el = (Element) nl.item(i);
// find the keyword target, classname and argument attributes
String wordTag = el.getFirstChild().getNodeValue();
String target = el.getAttribute("target");
String className = el.getAttribute("className");
String arg = el.getAttribute("arg");
String variable = el.getAttribute("variable");
int points = 0;
try{
points = Integer.valueOf(el.getAttribute("points"));
}catch (Exception e){
}
String learn = el.getAttribute("learn");
// split keyword by comma
String[] words = wordTag.split(",");
// loop through all words
for (String word : words) {
// trim the word to remove spaces
word = word.trim();
// construct a new keyword
Keyword keyword = new Keyword(word, target, className, arg, variable, points, learn );
// add the keyword to keywords array list
keywords.add(keyword);
}
}
}
// return all the keywords in the given node
return keywords;
}
// returns one of the invalid messages and move the index to the next message
public String getInvalidAnswer() {
// get current answer
String answer = invalidMessages.get(invalidMessageIndex);
// increase the index, if it is end of messages, reset the index to 0
invalidMessageIndex++;
if (invalidMessageIndex >= invalidMessages.size()) {
invalidMessageIndex = 0;
}
return answer;
}
// load cofig tags from data xml file
private void loadConfiguration() {
// get document element
Element docEle = dom.getDocumentElement();
// get all node names for invalid messages
NodeList node = docEle.getElementsByTagName("InvalidMessages");
// get all message nodes inside invalid messages node
NodeList nl = ((Element) node.item(0)).getElementsByTagName("message");
// if node is not null and has children
if (nl != null && nl.getLength() > 0) {
// loop through all children
for (int i = 0; i < nl.getLength(); i++) {
// get message node
Element el = (Element) nl.item(i);
// get message and add it to invalid messages array
String message = el.getFirstChild().getNodeValue();
invalidMessages.add(message);
}
}
}
}
The bot class manages conversation and calls specialised classes.
package bot;
import smallTalk.Morning;
import smallTalk.Afternoon;
import smallTalk.Evening;
import smallTalk.Night;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class Bot {
// Store all regular expression matches
private HashMap<String,String> dictionary;
// Default state to start the bot
String level = "0";
DataParser parser;
// default constructor
public Bot(String level, DataParser parser) {
dictionary = new HashMap<String,String>();
this.level = level;
this.parser = parser;
}
// get current state message
public String getMessage() {
State state = parser.getState(level);
return replaceMatches(state.getMessage()).trim();
}
// send user message to the bot and get the response
public String send(String message) {
String response = "";
State state = parser.getState(level);
// end of the tree
if (state.getKeywords().isEmpty()) {
this.level = "0";
}
// match the keyword with given message
Keyword match = parse(message, state.getKeywords());
// if no keyword is matched, display one of the invalid answers
if (match == null) {
response = parser.getInvalidAnswer();
} else {
// if match classname is provided, check to get the dynamic response
if (match.className.length() > 0) {
// check for Weather dynamic response
if (match.className.equals("Weather")) {
Weather weather = new Weather();
response = weather.getResponse(match.arg);
this.level = "0";
}
// check for News dynamic response
else if (match.className.equals("News")) {
News news = new News();
response = news.getResponse(match.arg);
this.level = "0";
}
else if (match.className.equals("Morning")) {
Morning morning = new Morning();
morning.wakeup();
}
else if (match.className.equals("Afternoon")) {
Afternoon afternoon = new Afternoon();
afternoon.midday();
}
else if (match.className.equals("Evening")) {
Evening evening = new Evening();
evening.dinner();
}
else if (match.className.equals("Night")) {
Night night = new Night();
night.late();
}
// check for Topic dynamic response
else if (match.className.equals("Topic")) {
Topic topic = new Topic();
topic.getTopic(match.arg);
}
} else {
// get the new state and return the new message
if (response.length() == 0) {
this.level = match.target;
state = parser.getState(level);
// if it is end of the tree
if (state.getKeywords().isEmpty()) {
response = this.getMessage();
this.level = "0";
}
}
}
}
return response;
}
// parse the given text to find best match in the keywords
private Keyword parse(String text, ArrayList<Keyword> keylist) {
// set the default match to none
int bestMatch = -1;
Keyword match = null;
// loop through keywords
for (int i = 0; i < keylist.size(); i++) {
// get number of matches of the keyword with given text
int matches = getMatches(text, keylist.get(i));
// if match is better than best match, replace it
if (matches > -1 && matches > bestMatch) {
match = keylist.get(i);
bestMatch = matches;
}
}
// add best answers regex variable value into the dictionary for future reference
if (match != null){
if(match.learn.length() > 0 ){
// get training data keyword and description
String subject = dictionary.get(match.learn);
String result = match.variableValue;
// create a new state for new trained data
ArrayList<String> messages = new ArrayList<String>();
messages.add(result);
State myState = new State(String.valueOf(parser.stateCounter),messages,new ArrayList());
parser.addState(myState);
// add the new trained keyword
Keyword keyword = new Keyword(subject, myState.getId(), "", "", "", 1, "" );
State state = parser.getState("1");
ArrayList<Keyword> keywords = state.getKeywords();
keywords.add(keyword);
}else{
if (match.variableValue.length() > 0){
dictionary.put(match.variable, match.variableValue);
}
}
}
return match;
}
// get number of matches of the given keywords in the given list
private int getMatches(String text, Keyword keyword) {
// no match by default
int result = -1;
// return 0 match when keyword is *
if(keyword.keyword.equals("*")){
return keyword.points;
}
// if regex is expected
if(keyword.variable.length() > 0){
String match = Regex.match(keyword.keyword, text);
if(match.length() > 0){
keyword.variableValue = match;
return keyword.points;
}
}
String[] words = keyword.keyword.split(" ");
// loop through list of the keywords
for (String word : words) {
// if current keyword is in the text, add points
if (text.toLowerCase().indexOf(word.toLowerCase()) >= 0) {
result = result + keyword.points + 1;
} else {
// return null if one of the keywords does not exists
return -1;
}
}
return result;
}
// replace given text with variables in the dictionary
public String replaceMatches(String text){
// replace variables within dictionary in the text
for (Map.Entry<String, String> entry : dictionary.entrySet()) {
text = text.replaceAll("\\["+entry.getKey() + "\\]", entry.getValue());
}
// remove empty variables tags
return Regex.clear(text);
}
}
The Context class passes the xml file source to data parser.
package bot;
public class Context {
public static String source = "newcontext.xml";
//method to get value of source called in dataParser
public static String getSource(){
return source;
}
//get the new topic from Topic Class and prepare to reload DataParser/Bot
public static void newSource(String currentTopic){
source = currentTopic;
}
}
Hello i am new to STAX and I have xml file as an example. Like this
<?xml version="1.0"?>
<data>
<name>
<sensitive>true</sensitive>
</name>
<dob>
<sensitive>false</sensitive>
</dob>
<email-id>
<sensitive>true</sensitive>
</email-id>
<ssn>
<sensitive>true</sensitive>
</ssn>
<bankaccountnumber>
<sensitive>true</sensitive>
</bankaccountnumber>
<licencenumber>
<sensitive>false</sensitive>
</licencenumber>
I want just feild name , whose sensitive value is true. In this example i want just Name,ssn, emailid and bankaccount number. So how can i do. Please anyone help me.
It is much more easier to use DOM. You can refer here : http://www.developerfusion.com/code/2064/a-simple-way-to-read-an-xml-file-in-java/ . Hope can help you
Use dom4j. Here is sample code that may help you :
private List<String> _listXPath = new ArrayList<String>();
public static void main(String[] args) {
Document document = DocumentHelper.parseText(xml);
treeWalk(document);
}
private void treeWalk(Document document) {
treeWalk( document.getRootElement() );
}
// Traverse xml
private void treeWalk(Element element) {
String line = "";
for ( int i = 0, size = element.nodeCount(); i < size; i++ ) {
Node node = element.node(i);
if ( node instanceof Element ) {
Element el = (Element) node;
for ( int j = 0, total = el.attributeCount(); j < total; j++ ) {
Attribute attribute = el.attribute(j);
line = attribute.getPath() + attribute.getValue();
_listXPath.add(line);
}
treeWalk( (Element) node );
}
else {
line = node.getPath() +node.getText();
_listXPath.add(line);
}
}
}
I have written a generic Partition class (a partition is a division of a set into disjoint subsets, called parts). Internally this is a Map<T,Integer> and a Map<Integer,Set<T>>, where the Integers are the labels of the parts. For example partition.getLabel(T t) gives the label of the part that t is in, and partition.move(T t, Integer label) moves t to the partition labelled by label (internally, it updates both the Maps).
But my method for moving a Collection of objects to a new part does not work. It seems that Set.removeAll() is affecting its argument. I think the problem is something like a ConcurrentModificationException, but I can't work it out. Sorry the code is rather long, but I have marked where the problem is (about half-way down), and the output at the bottom should make it clear what the problem is - at the end the partition is in an illegal state.
import java.util.*;
public class Partition<T> {
private Map<T,Integer> objToLabel = new HashMap<T,Integer>();
private Map<Integer,Set<T>> labelToObjs =
new HashMap<Integer,Set<T>>();
private List<Integer> unusedLabels;
private int size; // = number of elements
public Partition(Collection<T> objects) {
size = objects.size();
unusedLabels = new ArrayList<Integer>();
for (int i = 1; i < size; i++)
unusedLabels.add(i);
// Put all the objects in part 0.
Set<T> part = new HashSet<T>(objects);
for (T t : objects)
objToLabel.put(t,0);
labelToObjs.put(0,part);
}
public Integer getLabel(T t) {
return objToLabel.get(t);
}
public Set<T> getPart(Integer label) {
return labelToObjs.get(label);
}
public Set<T> getPart(T t) {
return getPart(getLabel(t));
}
public Integer newPart(T t) {
// Move t to a new part.
Integer newLabel = unusedLabels.remove(0);
labelToObjs.put(newLabel,new HashSet<T>());
move(t, newLabel);
return newLabel;
}
public Integer newPart(Collection<T> things) {
// Move things to a new part. (This assumes that
// they are all in the same part to start with.)
Integer newLabel = unusedLabels.remove(0);
labelToObjs.put(newLabel,new HashSet<T>());
moveAll(things, newLabel);
return newLabel;
}
public void move(T t, Integer label) {
// Move t to the part "label".
Integer oldLabel = getLabel(t);
getPart(oldLabel).remove(t);
if (getPart(oldLabel).isEmpty()) // if the old part is
labelToObjs.remove(oldLabel); // empty, remove it
getPart(label).add(t);
objToLabel.put(t,label);
}
public void moveAll(Collection<T> things, Integer label) {
// Move all the things from their current part to label.
// (This assumes all the things are in the same part.)
if (things.size()==0) return;
T arbitraryThing = new ArrayList<T>(things).get(0);
Set<T> oldPart = getPart(arbitraryThing);
// THIS IS WHERE IT SEEMS TO GO WRONG //////////////////////////
System.out.println(" oldPart = " + oldPart);
System.out.println(" things = " + things);
System.out.println("Now doing oldPart.removeAll(things) ...");
oldPart.removeAll(things);
System.out.println(" oldPart = " + oldPart);
System.out.println(" things = " + things);
if (oldPart.isEmpty())
labelToObjs.remove(objToLabel.get(arbitraryThing));
for (T t : things)
objToLabel.put(t,label);
getPart(label).addAll(things);
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("\nPARTITION OF " + size + " ELEMENTS INTO " +
labelToObjs.size() + " PART");
result.append((labelToObjs.size()==1 ? "" : "S") + "\n");
for (Map.Entry<Integer,Set<T>> mapEntry :
labelToObjs.entrySet()) {
result.append("PART " + mapEntry.getKey() + ": ");
result.append(mapEntry.getValue() + "\n");
}
return result.toString();
}
public static void main(String[] args) {
List<String> strings =
Arrays.asList("zero one two three".split(" "));
Partition<String> p = new Partition<String>(strings);
p.newPart(strings.get(3)); // move "three" to a new part
System.out.println(p);
System.out.println("Now moving all of three's part to the " +
"same part as zero.\n");
Collection<String> oldPart = p.getPart(strings.get(3));
//oldPart = Arrays.asList(new String[]{"three"}); // works fine!
p.moveAll(oldPart, p.getLabel(strings.get(0)));
System.out.println(p);
}
}
/* OUTPUT
PARTITION OF 4 ELEMENTS INTO 2 PARTS
PART 0: [two, one, zero]
PART 1: [three]
Now moving all of three's part to the same part as zero.
oldPart = [three]
things = [three]
Now doing oldPart.removeAll(things) ...
oldPart = []
things = []
PARTITION OF 4 ELEMENTS INTO 1 PART
PART 0: [two, one, zero]
*/
Using my debugger I place a breakpoint before the removeAll and I can see (as I suspected) that oldPart and things as the same collection so removing all elements clears that collection.
Your code is extremely confusing but as far as I can work out, oldPart and things are actually the same object. Set.removeAll() certainly doesn't affect its argument unless it is the same object as it's invoked on:
public boolean removeAll(Collection<?> c) {
boolean modified = false;
if (size() > c.size()) {
for (Iterator<?> i = c.iterator(); i.hasNext(); )
modified |= remove(i.next());
} else {
for (Iterator<?> i = iterator(); i.hasNext(); ) {
if (c.contains(i.next())) {
i.remove();
modified = true;
}
}
}
return modified;
}
Update:
The easy way to eliminate this is to use a copy of things in the moveAll() method. Indeed such a copy already exists.
T arbitraryThing = new ArrayList<T>(things).get(0);
This line creates but then instantly discards a copy of things. So I'd suggest replacing it with:
ArrayList<T> thingsToRemove = new ArrayList<T>(things)
T arbitraryThing = thingsToRemove.get(0);
And in the rest of the method, replace all references to things to thingsToRemove.