How to make string formatting mechanism in Java? - java

I'm trying to make a string formatting mechanism, which pretty much looks like the Winamp Advanced Title Formatting.
I have some 'variables' (or metadata fields) bound to object properties, in the form %varname%. So, for example, the %title% metadata field is bound to a song title, say 'Conquest of Paradise', the %artist% metadata field is bound to the song artist, say 'Vangelis', and the %feat% metadata field is bound to the featuring artists, say 'English Chamber Choir'.
Now I want to display the song depending on a given formatting, for example:
%title%[ (by %artist%[ featuring %feat%])]
Square brackets mean don't display unless (all) metadata inside the brackets were set. Nesting of square brackets should be possible.
So abovementioned formatting string says: display the metadata field %title% and, if %artist% is set (not an empty string), display (by %artist%), but if the %feat% metadata field is also non-empty, then display that field also. In the abovementioned example, it would become:
Conquest of Paradise (by Vangelis featuring English Chamber Choir)
Now how do I make such mechanism? Where do I start?
I guess that I have to tokenize the string and then per 'section' search for metadata tags?

I would build up a tree structure that represents the pattern. For your example, it would look like:
root
+ variable (title)
+ group
+ text (" (by ")
+ variable (artist)
+ group
+ text (" featuring ")
+ variable (feat)
+ text (")")
Then when you evaluate meta data against your tree, you store at the group level whether all variables and sub-groups in the group evaluated, and if so use the text.
Your tree classes would look something like:
interface Node { String evaluate(Map<String, String> metaData); }
class Group implements Node
{
private final List<Node> _children;
Group(final List<Node> children) { _children = children; }
#Override
public String evaluate(final Map<String, String> metaData)
{
final StringBuilder sb = new StringBuilder();
for (final Node node : _children)
{
final String subText = node.evaluate(metaData);
if (subText == null)
return null;
sb.append(subText);
}
return sb.toString();
}
}
class Text implements Node
{
private final String _text;
Text(final String text) { _text = text; }
#Override
public String evaluate(final Map<String, String> metaData)
{
return _text;
}
}
class Variable implements Node
{
private final String _variable;
Variable(final String variable) { _variable = variable; }
#Override
public String evaluate(final Map<String, String> metaData)
{
return metaData.get(_variable);
}
}
All that's left to do is to work out how to parse your string to create the tree structure.

Based on the suggestion of SimonC, I've written a tokenizer what executes what has been suggested, to split the formatting string into tokens.
public class Main {
private static void buildTree(String format) {
Stack<Token> st = new Stack<>();
StringBuilder sb = new StringBuilder();
GroupToken root = new GroupToken();
st.push(root);
boolean var = false;
for (int i = 0; i < format.length(); i++) {
char currentChar = format.charAt(i);
switch (currentChar) {
case '[':
String str = sb.toString();
sb.setLength(0); // Flush the StringBuilder
if (!str.equals("")) {
((GroupToken) st.peek()).add(new TextToken(str));
}
GroupToken gt = new GroupToken();
((GroupToken) st.peek()).add(gt);
st.push(gt);
break;
case ']':
str = sb.toString();
sb.setLength(0); // Flush the StringBuilder
if (!str.equals("")) {
((GroupToken) st.peek()).add(new TextToken(str));
}
st.pop();
break;
case '%':
var = !var;
if (var) {
str = sb.toString();
sb.setLength(0); // Flush the StringBuilder
if (!str.equals("")) {
((GroupToken) st.peek()).add(new TextToken(str));
}
}
else {
str = sb.toString();
sb.setLength(0); // Flush the StringBuilder
((GroupToken) st.peek()).add(new VariableToken(str));
}
break;
default:
sb.append(currentChar);
break;
}
}
// Process the last remains of the string buffer...
String str = sb.toString();
sb.setLength(0); // Flush the StringBuilder
if (!str.equals("")) {
((GroupToken) st.peek()).add(new TextToken(str));
}
st.pop();
System.out.println(root);
}
public static void main(String[] arguments) throws Exception {
buildTree("%title%[ (%alttitle%[, #%track%])]");
}
}
abstract class Token {
public abstract String toString(int indent);
}
class TextToken extends Token {
private String text;
public TextToken(String text) {
this.text = text;
}
#Override
public String toString() {
return toString(0);
}
#Override
public String toString(int indent) {
return "TextToken[\"" + this.text + "\"]\n";
}
}
class VariableToken extends Token {
private String text;
public VariableToken(String text) {
this.text = text;
}
#Override
public String toString() {
return toString(0);
}
#Override
public String toString(int indent) {
return "VariableToken[\"" + this.text + "\"]\n";
}
}
class GroupToken extends Token {
ArrayList<Token> tokens = new ArrayList<>();
public GroupToken() { }
public void add(Token token) {
this.tokens.add(token);
}
#Override
public String toString() {
return toString(0);
}
#Override
public String toString(int indent) {
String out = "GroupToken[\n";
for (Token t : this.tokens) {
out += StringUtils.pad("", 4 * (indent + 1), ' ') + t.toString(indent + 1);
}
out += StringUtils.pad("", 4 * indent, ' ') + "]\n";
return out;
}
}

Related

Why saving the char '�' to a file saves it as '?'?

I learned about Huffman Coding and tried to apply. So I made a very basic text reader that can only open and save files. And wrote a decorator that can be used to compress the text before saving (which uses Huffman Coding).
There was a bug that I couldn't find and after alot of debugging I figured out that when I compress the text, as a result the character � may be in the compressed text. For example, the text ',-.:BCINSabcdefghiklmnoprstuvwy gets compressed to 앐낧淧翵�ဌ䤺큕㈀.
I figured out that the bug lies in the saving function. When I save the compressed text, it changes every occurence of � to ?. For example, when saving 앐낧淧翵�ဌ䤺큕㈀, I get 앐낧淧翵?ဌ䤺큕㈀.
When I try to read the saved file to decompress it, I get a different string so the decompression fails.
What makes it more difficult is that the saving function alone works fine, but it doesn't work when using it in my code. the function looks like this:
public void save() throws IOException {
FileWriter fileWriter = new FileWriter(this.filename);
fileWriter.write(this.text);
fileWriter.close();
}
It's confusing that this.text at the moment of saving is 앐낧淧翵�ဌ䤺큕㈀ yet it saves it as 앐낧淧翵?ဌ䤺큕㈀.
As I said before, the function works fine when alone, but doesn't work in my code. I couldn't do any thing more that removing as much as possible from my code and and putting it here. Anyways, a breakpoint can be put at the function FileEditor::save and you'll find that this.text at the moment of saving is 앐낧淧翵�ဌ䤺큕㈀ and the content of the file is 앐낧淧翵?ဌ䤺큕㈀.
Code:
FileEditor is right below Main.
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.PriorityQueue;
import java.util.TreeMap;
import static pack.BitsManipulator.CHAR_SIZE_IN_BITS;
public class Main {
public static void main(String[] args) throws IOException {
String text = " ',-.:BCINSabcdefghiklmnoprstuvwy";
FileEditor fileEditor2 = new FileEditor("file.txt");
HuffmanDecorator compressor = new HuffmanDecorator(fileEditor2);
compressor.setText(text);
System.out.println(compressor.getText());
compressor.save();
}
}
class FileEditor implements BasicFileEditor {
private String filename;
private String text;
public FileEditor(String filename) throws IOException {
this.filename = filename;
File file = new File(filename);
StringBuilder builder = new StringBuilder();
if (!file.createNewFile()) {
FileReader reader = new FileReader(file);
int ch;
while ((ch = reader.read()) != -1)
builder.append((char) ch);
}
this.text = builder.toString();
}
#Override
public String getText() {
return text;
}
#Override
public void setText(String text) {
this.text = text;
}
#Override
public void save() throws IOException {
FileWriter fileWriter = new FileWriter(this.filename);
fileWriter.write(this.text);
fileWriter.close();
}
}
interface BasicFileEditor {
String getText();
void setText(String text);
void save() throws IOException;
}
abstract class FileEditorDecorator implements BasicFileEditor {
FileEditor fileEditor;
public FileEditorDecorator(FileEditor fileEditor) {
this.fileEditor = fileEditor;
}
#Override
public String getText() {
return fileEditor.getText();
}
#Override
public void setText(String text) {
fileEditor.setText(text);
}
#Override
public void save() throws IOException {
String oldText = getText();
setText(getModifiedText());
fileEditor.save();
setText(oldText);
}
protected abstract String getModifiedText();
}
class HuffmanDecorator extends FileEditorDecorator {
public HuffmanDecorator(FileEditor fileEditor) {
super(fileEditor);
}
#Override
protected String getModifiedText() {
HuffmanCodingCompressor compressor = new HuffmanCodingCompressor(getText());
return compressor.getCompressedText();
}
}
class HuffmanCodingCompressor {
String text;
public HuffmanCodingCompressor(String text) {
this.text = text;
}
public String getCompressedText() {
EncodingBuilder builder = new EncodingBuilder(text);
return builder.getCompressedText();
}
}
class Node implements Comparable<Node> {
public Node left;
public Node right;
public int value;
public Character character;
public Node(Node left, Node right, int value) {
this(left, right, value, null);
}
public Node(Node left, Node right, int value, Character character) {
this.left = left;
this.right = right;
this.character = character;
this.value = value;
}
#Override
public int compareTo(Node o) {
return this.value - o.value;
}
public boolean isLeafNode() {
return left == null && right == null;
}
Node getLeft() {
if (left == null)
left = new Node(null, null, 0);
return left;
}
Node getRight() {
if (right == null)
right = new Node(null, null, 0);
return right;
}
}
class EncodingBuilder {
private String text;
private Node encodingTree;
private TreeMap<Character, String> encodingTable;
public EncodingBuilder(String text) {
this.text = text;
buildEncodingTree();
buildEncodingTableFromTree(encodingTree);
}
private void buildEncodingTableFromTree(Node encodingTree) {
encodingTable = new TreeMap<>();
buildEncodingTableFromTreeHelper(encodingTree, new StringBuilder());
}
public void buildEncodingTableFromTreeHelper(Node root, StringBuilder key) {
if (root == null)
return;
if (root.isLeafNode()) {
encodingTable.put(root.character, key.toString());
} else {
key.append('0');
buildEncodingTableFromTreeHelper(root.left, key);
key.deleteCharAt(key.length() - 1);
key.append('1');
buildEncodingTableFromTreeHelper(root.right, key);
key.deleteCharAt(key.length() - 1);
}
}
public void buildEncodingTree() {
TreeMap<Character, Integer> freqArray = new TreeMap<>();
for (int i = 0; i < text.length(); i++) {
// improve here.
char c = text.charAt(i);
if (freqArray.containsKey(c)) {
Integer freq = freqArray.get(c) + 1;
freqArray.put(c, freq);
} else {
freqArray.put(c, 1);
}
}
PriorityQueue<Node> queue = new PriorityQueue<>();
for (Character c : freqArray.keySet())
queue.add(new Node(null, null, freqArray.get(c), c));
if (queue.size() == 1)
queue.add(new Node(null, null, 0, '\0'));
while (queue.size() > 1) {
Node n1 = queue.poll();
Node n2 = queue.poll();
queue.add(new Node(n1, n2, n1.value + n2.value));
}
encodingTree = queue.poll();
}
public String getCompressedTextInBits() {
StringBuilder bits = new StringBuilder();
for (int i = 0; i < text.length(); i++)
bits.append(encodingTable.get(text.charAt(i)));
return bits.toString();
}
public String getCompressedText() {
String compressedInBits = getCompressedTextInBits();
int remainder = compressedInBits.length() % CHAR_SIZE_IN_BITS;
int paddingNeededToBeDivisibleByCharSize = CHAR_SIZE_IN_BITS - remainder;
String compressed = BitsManipulator.convertBitsToText(compressedInBits + "0".repeat(paddingNeededToBeDivisibleByCharSize));
return compressed;
}
}
class BitsManipulator {
public static final int CHAR_SIZE_IN_BITS = 16;
public static int bitsInStringToInt(String bits) {
int result = 0;
for (int i = 0; i < bits.length(); i++) {
result *= 2;
result += bits.charAt(i) - '0';
}
return result;
}
public static String convertBitsToText(String bits) {
if (bits.length() % CHAR_SIZE_IN_BITS != 0)
throw new NumberOfBitsNotDivisibleBySizeOfCharException();
StringBuilder result = new StringBuilder();
for (int i = 0; i < bits.length(); i += CHAR_SIZE_IN_BITS)
result.append(asciiInBitsToChar(bits.substring(i, i + CHAR_SIZE_IN_BITS)));
return result.toString();
}
public static char asciiInBitsToChar(String bits) {
return (char) bitsInStringToInt(bits);
}
public static class NumberOfBitsNotDivisibleBySizeOfCharException extends RuntimeException {
}
}
� is the Unicode replacement character U+FFFD. If you encode that in a non-unicode encoding, it will get converted to a regular question mark, as non-unicode encodings can't encode all unicode characters, and this provides a "safety" (i.e. convert everything to question marks that we can't encode).
You seem to be confused about the difference between binary data and text data, leading you to look at compressed data as if it were Korean text instead of binary data. You need to store (and observe) the data as bytes, not chars or Strings.

Make an object of a class from a string in java

I have different classes, each receives strings and convert it to different html formats.
Then I have a chooser class where i have switch cases to divert the strings e.g.
i send the strings to chooser and stylename like this
Chooser chooser = new Chooser();
String text = chooser.format(sometext, stylename);
the Chooser class is like this:
public String format(String sometext, String stylename) {
switch (stylename) {
case "NewStyle":
NewStyle ns = new NewStyle();
str = ns.refprocess(sometext);
break;
case "Anotherstyle":
Anotherstyle as = new Anotherstyle();
str = as.refprocess(sometext);
break;
case "Tet_Letters":
Turk_J_Chem tet_letters = new Turk_J_Chem();
str = tet_letters.refprocess(sometext);
break;
}
}
it there any short way? so that when i send the stylename as String, it converts the to Class, make its object and then send the sometext to that class only?
I assume that you have an interface:
static interface Style {
String refprocess(String text);
}
and 3 implemntations:
static class NewStyle implements Style {
#Override
public String refprocess(final String text) {
return "new style of " + text;
}
}
static class Anotherstyle implements Style {
#Override
public String refprocess(final String text) {
return "Another style of " + text;
}
}
static class Turk_J_Chem implements Style {
#Override
public String refprocess(final String text) {
return "Turk_J_Chem's style of " + text;
}
}
Then you can create an enum of classes, and format using the enum:
enum Styles1 {
NEW(NewStyle.class, "NewStyle"),
ANOTHER(Anotherstyle.class, "Anotherstyle"),
TET_LETTERS(Turk_J_Chem.class, "Tet_Letters");
String str;
Class<? extends Style> clazz;
Styles1(final Class<? extends Style> clazz, final String str) {
this.clazz = clazz;
this.str = str;
}
}
static String formatUsingEnum1(final String sometext, final String stylename) {
for (final Styles1 style : Styles1.values()) {
if (style.str.equals(stylename)) {
try {
return style.clazz.newInstance().refprocess(sometext);
} catch (final Exception e) {
break;
}
}
}
throw new NotImplementedException(stylename);
}
Or you can populate the enum with real instances:
enum Styles2 {
NEW(new NewStyle(), "NewStyle"),
ANOTHER(new Anotherstyle(), "Anotherstyle"),
TET_LETTERS(new Turk_J_Chem(), "Tet_Letters");
String str;
Style style;
Styles2(final Style instance, final String str) {
style = instance;
this.str = str;
}
}
static String formatUsingEnum2(final String sometext, final String stylename) {
for (final Styles2 style : Styles2.values()) {
if (style.str.equals(stylename)) {
try {
return style.style.refprocess(sometext);
} catch (final Exception e) {
break;
}
}
}
throw new NotImplementedException(stylename);
}
But you can insert an abstract function into the enum, with inline implementation for all instances:
enum Styles3 {
NewStyle() {
#Override
String refprocess(final String text) {
return "new style of " + text;
}
},
Anotherstyle {
#Override
String refprocess(final String text) {
return "Another style of " + text;
}
},
TET_LETTERS {
#Override
String refprocess(final String text) {
return "Turk_J_Chem's style of " + text;
}
};
abstract String refprocess(String text);
}
static String formatUsingEnum3(final String sometext, final String stylename) {
for (final Styles3 style : Styles3.values()) {
if (style.name().equalsIgnoreCase(stylename)) {
try {
return style.refprocess(sometext);
} catch (final Exception e) {
break;
}
}
}
throw new NotImplementedException(stylename);
}
Enjoy...

Create map of maps from eclipse toString()

Eclipse can auto-generate a toString() method from a object's fields. If those fields are objects then they too may have similarly auto-generated toString() methods.
e.g. a President object might look like this:
President [country=USA, name=Name [title=Mr, forename=Barack, surname=Obama], address=Address [houseNumber=1600, street=Pennsylvania Avenue, town=Washington]]
which is easier to read if I format it:
President [
country=USA,
name=Name [
title=Mr,
forename=Barack,
surname=Obama],
address=Address [
houseNumber=1600,
street=Pennsylvania Avenue,
town=Washington]]
What is the best way to parse this String to create a map of maps?
I've got a solution, but it's not pretty. I was hoping to be able to avoid the low level String manipulation somehow, but here it is:
import java.util.LinkedHashMap;
import java.util.Map;
public class MappedObject {
public String className;
public Map<String, String> leafFields = new LinkedHashMap<>();
public Map<String, MappedObject> treeFields = new LinkedHashMap<>();
#Override
public String toString() {
return "[className=" + className
+ (leafFields.isEmpty() ? "" : ", leafFields=" + leafFields)
+ (treeFields.isEmpty() ? "" : ", treeFields=" + treeFields)
+ "]";
}
public static MappedObject createFromString(String s) {
MappedObject mo = new MappedObject();
new Mapper(s).mapObject(mo);
return mo;
}
private static class Mapper {
private String s;
public Mapper(String s) {
this.s = s;
}
private String mapObject(MappedObject mo) {
mo.className = removeFirstNCharacters(s.indexOf(' '));
while (s.contains("=")) {
removeLeadingNonLetters();
String key = removeFirstNCharacters(s.indexOf('='));
removeFirstNCharacters(1); // remove the =
String leafValue = getLeafValue();
if (leafValue != null) {
mo.leafFields.put(key, leafValue);
if (s.startsWith("]")) { // that was the last field in the tree
return s;
}
} else {
MappedObject treeField = new MappedObject();
mo.treeFields.put(key, treeField);
s = new Mapper(s).mapObject(treeField);
}
}
return s; // s contains only close brackets - ]
}
private void removeLeadingNonLetters() {
int i = 0;
while (!Character.isLetter(s.charAt(i))) {
i++;
}
removeFirstNCharacters(i);
}
private String removeFirstNCharacters(int n) {
String value = s.substring(0, n);
s = s.substring(value.length());
return value;
}
private String getLeafValue() {
int endIndex = getEndIndex();
if (!s.contains("[") || s.indexOf('[') > endIndex) {
return removeFirstNCharacters(endIndex);
}
return null;
}
/** The end of the value, if it's a leaf field. */
private int getEndIndex() {
if(s.contains(",")) {
return Math.min(s.indexOf(','), s.indexOf(']'));
}
return s.indexOf(']');
}
}
}

need to split the string using get() and set() methods

I have to use getters and setters for this code and
actually i'm using two classes to get the result
here is Ndc class:
package java4u.com;
public class Ndc {
private String ndcQUAL;
private String ndcCODE;
private String ndcUNIT;
private String ndcQTY;
String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public String getndcQUAL() {
if(str.contains("N4"))
{
return "N4";
}
else
{
return "";
}
}
public void setndcQUAL(String getndcQUAL) {
this.ndcQUAL = getndcQUAL;
}
public String getndcCODE() {
if(str.contains("N4")){
int i=str.indexOf("N4");
str=str.substring(i+2,i+13);
return str;
}
else
{
return "";
}
}
public void setndcCODE(String getndcCODE) {
this.ndcCODE = getndcCODE;
}
public String getndcUNIT() {
if(str.contains("N4")) {
str=str.substring(i+13,i+15);
return str;
}else
{
return "";
}
}
public void setndcUNIT(String getndcUNIT) {
this.ndcUNIT = getndcUNIT;
}
public String getndcQTY() {
if(str.contains("N4")) {
do {
int i=str.indexOf(getndcUNIT());
str=str.substring(i,i++);
return str;
} while(str.length()<=35 || str.contains("N4") || str.contains("TPL"));
else
{
return "";
}
}
public void setndcQTY(String getndcQTY) {
this.ndcQTY = getndcQTY;
}
}
here i'm using str variable and the string will be entered during runtime and the condition is if string contains "N4" value then the loop should be continue else return space.
and I have four methods in this program and
getNdcQUAL() method should return "N4" if string contains "N4" value
and getNdcCODE() method should display next 11 digits after the "N4" for this case I shouldn't mention str.substring(2,13)..I should find the position of NdcQUAL and from there to next 11 digits will be print..
and getNdcUNIT() method should display next two bytes qualifier after the 11 digits for this case also I should find the position of NdcCODE and from there to 2 digits
and finally getNdcQTY() method should return the data after the NdcUNIT for this case also I should find the position of NdcUNIT and from there to untill one of the condition is met
here is my main class
package java4u.com;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor.GetterSetterReflection;
public class Test {
public static String getStr(String str)
{
return str;
}
public static void main(String args[]) {
Ndc ndc=new Ndc();
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println("enter a string:");
br.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
couldn't understand how to pass the string value from Ndc.java to Test.java also couldn't get how to pass other methods from Ndc.java to Test.java
here is the sample output
str=N412345678923UN2345.677
it should return
N4
12345678923
UN
2345.67
please help me!!!!!!
Since you don't have a constructor. You need to manually set the str
If this N412345678923UN2345.677 is the br.readLine(). Then you need to set it in the for your NDC object
String str = br.readLine();
ndc.setStr(str); // now the str is set in your ndc object.
System.out.println(ndc.getndcCODE());
System.out.println(ndc.getndcUNIT());
System.out.println(ndc.getndcCQTY());
You should first pass the string like this :
ndc.setndcQUAL(yourString);
then get the required value :
System.out.print(ndc.getndcQUAL());
Your approach has one major flaw - you need to execute the methods in a predefined order, else it will extract wrong data. You can however use your setStr(String str) method to initialize all proper fields and then just use your getter methods to return the values you've set within your setStr(...) method:
public class Ndc
{
private String ndcQUAL;
private String ndcCODE;
private String ndcUNIT;
private String ndcQTY;
public void setStr(String str)
{
int pos = 0;
if (str.contains("N4"))
{
pos = str.indexOf("N4");
this.ndcQUAL = str.substring(pos, pos+=2);
this.ndcCODE = str.substring(pos, pos+=11);
this.ndcUNIT = str.substring(pos, pos+=2);
String data = str.substring(pos);
// trim the data at the end corresponding to the provided class logic
int p = data.length();
if (data.contains("N4"))
{
p = data.indexOf("N4");
}
else if (data.contains("TLP"))
{
p = data.indexOf("TLP");
}
if (p > 35)
p = 35;
this.ndcQTY = data.substring(0, p);
}
else
this.ndcQUAL = "";
}
public String getndcQUAL()
{
return this.ndcQUAL;
}
public String getndcCODE()
{
return this.ndcCODE;
}
public String getndcUNIT()
{
return this.ndcUNIT;
}
public String getndcQTY()
{
return this.ndcQTY;
}
}
To break the loop if no valid N4 string was entered, you first have to define a kind of loop first and check the getndcQUAL() return value if it equals N4 after you've assigned the input string to setStr(...):
public class Test
{
public static void main(String args[])
{
Ndc ndc=new Ndc();
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
try
{
do
{
System.out.println("enter a string:");
ndc.setStr(br.readLine());
System.out.println("QUAL: "+ndc.getndcQUAL());
System.out.println("CODE: "+ndc.getndcCODE());
System.out.println("UNIT: "+ndc.getndcUNIT());
System.out.println("QTY: "+ndc.getndcQTY());
}
while("N4".equals(ndc.getndcQUAL()));
}
catch (IOException e)
{
e.printStackTrace();
}
}
}

How do you store and manipulate retrieved information from an RSS Feed in Java?

Well I've run into another problem with RSSParsing.
Here's what I've done so far.
I've successfully accessed the data from the RSSFeed I want.
I've stored the information within it without a problem (to the best of my knowledge) to an Item class object. This class takes in Title, Description, Link, Publication Date.
public class Item {
private String link;
private String title;
private String pubDate;
private String description;
// Default Constructor
public Item()
{
link = new String();
title = new String();
pubDate = new String();
description = new String();
}
// Parameterized Constructor
public Item(String iTitle, String iDescription, String iLink, String iPubDate)
{
link = iLink;
title = iTitle;
pubDate = iPubDate;
description = iDescription;
}
public void setDate(String newPubDate)
{
pubDate = newPubDate;
}
public void setLink(String newLink)
{
link = newLink;
}
public void setTitle(String newTitle)
{
title = newTitle;
}
public void setDescription(String newDescription)
{
description = newDescription;
}
public String getDate()
{
return pubDate;
}
public String getLink()
{
return link;
}
public String getTitle()
{
return title;
}
public String getDescription()
{
return description;
}
public String toString()
{
return "Title: " + title + "\n" + "Publication Date: " + pubDate + "\n" + "Description: " + description + "\n" + "Link: " + link;
}
The following is my RSSParser handler class
import org.xml.sax.Attributes;
import lists.LinkedUnorderedList;
import org.xml.sax.helpers.DefaultHandler;
public class RSSParser extends DefaultHandler{
int itemCount = 0;
boolean item = false;
boolean link = false;
boolean title = false;
boolean pubDate = false;
boolean description = false;
Item theItem = new Item();
String itemPubDate = new String();
LinkedUnorderedList<Item> theUnorderedList = new LinkedUnorderedList();
public void startDocument()
{
System.out.println("Starts Parsing the Document.....\n");
}
public void endDocument()
{
System.out.println(theUnorderedList + "\n\n" + itemCount);
System.out.println("\nEnds parsing Document...");
}
public void startElement(String nameSpaceURI, String localName, String qName, Attributes atts)
{
if (qName.equalsIgnoreCase("item"))
{
theUnorderedList.addToRear(theItem);
theItem = new Item();
itemCount++;
}
else if ( qName.equalsIgnoreCase("link") )
{
link = true;
}
else if ( qName.equalsIgnoreCase("title") )
{
title = true;
}
else if ( qName.equalsIgnoreCase("pubDate") )
{
pubDate = true;
}
else if ( qName.equalsIgnoreCase("description") )
{
description= true;
}
}
public void endElement(String nameSpaceURI, String localName, String qName, Attributes atts)
{
System.out.print("End Element: " + qName );
}
public void characters(char[] ch, int start, int length)
{
if ( title )
{
//System.out.println("Title: " + new String( ch, start, length ) );
theItem.setTitle( new String( ch, start, length ) );
title = false;
}
else if ( link )
{
//System.out.println("Link: " + new String( ch, start, length ) );
theItem.setLink( new String( ch, start, length ) );
link = false;
}
else if ( description )
{
//System.out.println("Description: " + new String( ch, start, length ) );
theItem.setDescription( new String( ch, start, length ) );
description = false;
}
else if ( pubDate )
{
itemPubDate = new String( ch, start, length );
//System.out.println("PubDate: " + itemPubDate + "\nItemCount: " + itemCount + "\n\n");
theItem.setDate( new String( ch, start, length ) );
pubDate = false;
}
} // ends characters Method
Lastly is my Application class
//import java.net.URL;
//import java.util.Scanner;
import java.io.IOException;
import org.xml.sax.XMLReader;
import org.xml.sax.SAXException;
//import java.io.InputStreamReader;
import org.xml.sax.helpers.XMLReaderFactory;
public class Project4 {
public static void main (String [] args) throws IOException, SAXException
{
XMLReader read = XMLReaderFactory.createXMLReader();
RSSParser parser= new RSSParser();
read.setContentHandler(parser);
read.parse("http://feeds.ign.com/ign/games-articles");
} // Ends main
}
This works so far. The commented coded printed out what I wanted, which was to print the list of items I've stored in the linked list. My main goal is to put all these items in an UnorderedLinkedList which i've done correctly. But my question is how do I give the user access to this list in the application class? For example I want to be able to present the user with options on removing an item from the list. I know the methods for the linked list and how to create a GUI but to be clear, I don't know how access this list from the application class. Or am I creating the LinkedList in the wrong place?
Thanks
You need to move the RSSParser to be a variable in your Project4 class instead and provide methods to access it. Your static main method should instantiate an instance of Project4 and create a new RSSParser(). Use that instance to parse the feed and create a getter method to gain access to it from your GUI.
For example, something like this:
public class Project4 {
private parser RSSParser;
public RSSParser getParser() {
return parser
}
public static void main (String [] args) throws IOException, SAXException {
Project4 p = new Project4();
XMLReader read = XMLReaderFactory.createXMLReader();
p.parser= new RSSParser();
read.setContentHandler(p.parser);
read.parse("http://feeds.ign.com/ign/games-articles");
/// loop here and connect up your GUI
}
}
On a side note, you might want to take a look at the ROME project for parsing RSS feeds.

Categories

Resources