Skip to content

Commit

Permalink
Merge pull request #104 from smigielski/structureddocuments
Browse files Browse the repository at this point in the history
Structure documents
  • Loading branch information
lordofthejars committed Nov 1, 2013
2 parents fb4da9b + 6f70a8e commit 6631101
Show file tree
Hide file tree
Showing 12 changed files with 917 additions and 47 deletions.
172 changes: 171 additions & 1 deletion README.asciidoc
Expand Up @@ -211,7 +211,9 @@ Options options = options().inPlace(true).attributes(attributes).get();
String render = asciidoctor.renderFile("target/test-classes/rendersample.asciidoc", options);
...
----
----

=== Document Header

+readDocumentHeader+ retrieve information from the header of an AsciiDoc document without parsing or rendering the entire document.
This method returns an instance of +org.asciidoctor.DocumentHeader+ with all information from the header filled.
Expand Down Expand Up @@ -255,6 +257,174 @@ System.out.println(revisionInfo.getRemark()); <7>
<6> prints "1.0"
<7> prints "First draft"

=== Document structure

+readDocumentStructure+ provides easy and useful way of parsing asciidoc file into
the structured object. First of all it gathers exactly the same information as
+readDocumentHeader+ and puts it in +header+ filed of +StructuredDocument+ object.
Actual content of the file is split into separate ContentParts based on blocks of
the content.

There are few possible use cases of using this feature, please consider
following examples:

[source]
.AsciiDoc document with two blocks defined by section titles
----
= Sample Document
== Section one
This is content of section one
== Section two
And content of section two
...
----

Each section defines new content part. List of all parts can be get by +getParts+ method
on +StructuredDocument+. Each part will than contain of title (ie. "Section one") and
rendered text content as html.

[source]
.Print content of each part
----
for (ContentPart part : document.getParts()){
System.out.println(part.getTitle());
System.out.println("----");
System.out.println(part.getContent);
System.out.println("----");
}
----

[source]
.AsciiDoc document with two blocks defined by styles
----
= Sample Document
[style one]
This is content of first content part
[[partId]]
[style two,role="partRole"]
--
And content of second content part
This block can be as long as you want.
--
----

This way you can then use methods like getPartByStyle to retrieve particular content parts.
[source]
.Retrieve content part by style
----
ContentPart style_two = document.getPartByStyle("style two");
// other possible way of retrieving parts:
ContentPart style_two = document.getPartById("partId")
ContentPart style_two = document.getPartByRole("partRole")
//and also for lists
List<ContentPart> parts = document.getPartsByStyle("style two");
List<ContentPart> parts = document.getPartsByRole("partRole");
List<ContentPart> parts = document.getPartsByContext("open");
----

Really nice thing about it is possibility to parse images to Image object that you can use
later to embed in html page directly from your java code or manipulate in any other way.

[source]
.Define images
----
[Images]
image::src/some{sp}image{sp}1.JPG[TODO title1,link="link1.html"]
image::src/some{sp}image{sp}2.JPG[TODO title2,link="link2.html"]
----

to get a list of images defined in the document and then to process images:

[source]
.Retrieve image information
----
List<ContentPart> images = document.getPartsByContext("image");
for (ContentPart image : images){
String src = (String) image.getAttributes().get("target");
String alt = (String) image.getAttributes().get("alt");
String link = (String) image.getAttributes().get("link");
}
----

As of final example consider following complete use case:

[source]
.AsciiDoc document with product definition
----
= Sample product
v1.0, 2013-10-12
:hardbreaks:
:price: 70 pln
:smallImage: photos/small/small_image.jpg
[Description]
short product description
[Images]
image::photos/image1.jpg[title]
image::photos/image2.jpg[title]
[Detail]
--
Detail information about product. Note that you can use all asciidoc features here like:
.simple list
* lists
* images
* titles
* further blocks
[role=text-center]
also you can also add css style by assigning role to the text.
--
----

and the way it can be than transformed to java object:
[source]
.Java method for getting product
----
Product product = new Product();
product.setTitle(document.getHeader().getDocumentTitle());
product.setPrice(new Price((String) document.getHeader().getAttributes().get("price")));
product.setSmallImage(new Image((String)document.getHeader().getAttributes().get("smallImage"),product.getTitle()));
product.setDescription(document.getPartByStyle("description").getContent());
List<ContentPart> images = document.getPartsByContext("image");
for (ContentPart image : images) {
Image image = new Image();
image.setSrc((String) image.getAttributes().get("target"));
image.setAlt((String) image.getAttributes().get("alt"));
product.getImages().add(image);
}
product.setDetail(document.getPartByStyle("detail").getContent());
----

Last feature of structure document is possibility to configure how deeply should blocks
be processed. Default is one level only so if you want to have more nested structure add
STRUCTURE_MAX_LEVEL parameter to processing options.

[source]
.Configuration of the structure document processing
----
Map<String,Object> parameters = new HashMap<String, Object>();
parameters.put(Asciidoctor.STRUCTURE_MAX_LEVEL, 2);
StructuredDocument document = asciidoctor.readDocumentStructure(
new File("target/test-classes/documentblocks.asciidoc"),
parameters
);
----

=== Utilities

A utility class for searching all asciidoc files present in a root folder and all its subfolders is given. In fact it finds all files that end up with _.asc_, _.asciidoc_, _.ad_ or _.adoc_. This class is +AsciiDocDirectoryWalker+.
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/org/asciidoctor/Asciidoctor.java
Expand Up @@ -20,6 +20,8 @@
*/
public interface Asciidoctor {

public static final String STRUCTURE_MAX_LEVEL = "STRUCTURE_MAX_LEVEL";

/**
* Parse the AsciiDoc source input into an Document {@link DocumentRuby} and
* render it to the specified backend format.
Expand Down Expand Up @@ -273,6 +275,47 @@ String[] renderFiles(Collection<File> asciidoctorFiles,
String[] renderFiles(Collection<File> asciidoctorFiles,
OptionsBuilder options);

/**
* Reads and creates structured document containing header and content chunks.
* By default it dig only one level down but it can be tweak by setting STRUCTURE_MAX_LEVEL
* option.
*
* @param filename
* to read the attributes.
* @param options
* a Hash of options to control processing (default: {}).
* @return structured document.
*/
StructuredDocument readDocumentStructure(File filename,Map<String,Object> options);

/**
* Reads and creates structured document containing header and content chunks.
* By default it dig only one level down but it can be tweak by setting STRUCTURE_MAX_LEVEL
* option.
*
* @param content
* where rendered content is written. Writer is flushed, but not
* closed.
* @param options
* a Hash of options to control processing (default: {}).
* @return structured document.
*/
StructuredDocument readDocumentStructure(String content,Map<String,Object> options);

/**
* Reads and creates structured document containing header and content chunks.
* By default it dig only one level down but it can be tweak by setting STRUCTURE_MAX_LEVEL
* option.
*
* @param contentReader
* where asciidoc content is read.
* @param options
* a Hash of options to control processing (default: {}).
* @return structured document.
*/
StructuredDocument readDocumentStructure(Reader contentReader,Map<String,Object> options);


/**
* Reads only header parameters instead of all document.
*
Expand Down
77 changes: 77 additions & 0 deletions src/main/java/org/asciidoctor/ContentPart.java
@@ -0,0 +1,77 @@
package org.asciidoctor;

import java.util.List;
import java.util.Map;

public class ContentPart {
private String id;
private int level;
private String context;
private String style;
private String role;
private String title;
private Map<String, Object> attributes;
private String content;
private List<ContentPart> parts;

private ContentPart() {
super();
}

public String getId() {
return id;
}

public int getLevel() {
return level;
}

public String getContext() {
return context;
}

public String getStyle() {
return style;
}

public String getRole() {
return role;
}

public String getTitle() {
return title;
}

public Map<String, Object> getAttributes() {
return attributes;
}

public String getContent() {
return content;
}

public List<ContentPart> getParts() {
return parts;
}

public void setParts(List<ContentPart> parts) {
this.parts = parts;
}

public static ContentPart createContentPart(String id, int level,String context, String title,
String style, String role, Map<String, Object> attributes,
String textContent) {
ContentPart contentPart = new ContentPart();
contentPart.level=level;
contentPart.id=id;
contentPart.context=context;
contentPart.style=style;
contentPart.role=role;
contentPart.title=title;
contentPart.attributes=attributes;
contentPart.content=textContent;

return contentPart;
}

}

0 comments on commit 6631101

Please sign in to comment.