テンプレート処理中にエラーが発生しました。
Java method "com.liferay.portal.json.JSONFactoryImpl.createJSONObject(String)" threw an exception when invoked on com.liferay.portal.json.JSONFactoryImpl object "com.liferay.portal.json.JSONFactoryImpl@6b638fb3"; see cause exception in the Java stack trace.

----
FTL stack trace ("~" means nesting-related):
	- Failed at: navigationJSONObject = jsonFactoryUti...  [in template "8911408109993434201#23484949#LEARN-ARTICLE-NAV" at line 4, column 9]
----
1<#assign 
2	groupFriendlyURL = themeDisplay.getScopeGroup().getFriendlyURL() 
3	groupPathFriendlyURLPublic = themeDisplay.getPathFriendlyURLPublic() + groupFriendlyURL 
4	navigationJSONObject = jsonFactoryUtil.createJSONObject(navigation.getData()) 
5	navigationMenuItems = 
6
7			"Analytics Cloud": { 
8				"image": "/documents/d${groupFriendlyURL}/analytics_c-svg", 
9				"title": "Analytics Cloud", 
10				"url": "analytics-cloud" 
11			}, 
12			"Commerce": { 
13				"image": "/documents/d${groupFriendlyURL}/commerce_product-svg", 
14				"title": "Commerce", 
15				"url": "commerce" 
16			}, 
17			"DXP": { 
18				"image": "/documents/d${groupFriendlyURL}/dxp_p-svg", 
19				"title": "DXP / Portal", 
20				"url": "dxp" 
21			}, 
22			"Liferay Cloud": { 
23				"image": "/documents/d${groupFriendlyURL}/dxp_c-svg", 
24				"title": "Liferay Cloud", 
25				"url": "liferay-cloud" 
26			}, 
27			"Reference": { 
28				"image": "/documents/d${groupFriendlyURL}/reference-svg", 
29				"title": "Reference", 
30				"url": "reference" 
31
32
33 
34	breadcrumbJSONArray = navigationJSONObject.getJSONArray("breadcrumb") 
35	childrenJSONArray = navigationJSONObject.getJSONArray("children") 
36	parentJSONObject = navigationJSONObject.getJSONObject("parent") 
37	productJSONObject = breadcrumbJSONArray.getJSONObject(breadcrumbJSONArray.length()-1)!navigationJSONObject.getJSONObject("self") 
38	siblingsJSONArray = navigationJSONObject.getJSONArray("siblings") 
39/> 
40 
41<div class="learn-article-nav"> 
42	<#if productJSONObject?has_content && productJSONObject.getString("title")?has_content && navigationMenuItems[productJSONObject.getString("title")]?has_content && navigationMenuItems[productJSONObject.getString("title")].title?has_content> 
43		<div 
44			class="dropdown learn-article-nav-root learn-dropdown" 
45
46			<div class="learn-article-nav-item"> 
47				<div class="d-flex"> 
48					<div class="learn-article-nav-image"> 
49						<img 
50							class="lexicon-icon lexicon-icon-caret-bottom product-icon" 
51							role="presentation" 
52							src='${navigationMenuItems[productJSONObject.getString("title")].image}' 
53							viewBox="0 0 512 512" 
54						/> 
55					</div> 
56 
57					<span class="learn-article-nav-text">${navigationMenuItems[productJSONObject.getString("title")].title}</span> 
58				</div> 
59 
60				<div id="dropdown-icon"> 
61					<svg 
62						class="lexicon-icon lexicon-icon-caret-bottom" 
63						role="presentation" 
64						viewBox="0 0 512 512" 
65
66						<use xlink:href="/o/admin-theme/images/clay/icons.svg#caret-bottom"></use> 
67					</svg> 
68				</div> 
69			</div> 
70 
71			<ul class="dropdown-menu learn-dropdown-menu"> 
72				<#list navigationMenuItems as key, value> 
73					<li> 
74						<a 
75							class="dropdown-item learn-article-nav-item" 
76							href="/w/${navigationMenuItems[key].url}/index" 
77							tabindex="4" 
78
79							<span class="d-flex"> 
80								<span class="learn-article-nav-image"> 
81									<img 
82										class="lexicon-icon lexicon-icon-caret-bottom product-icon mt-0 mr-2" 
83										role="presentation" 
84										src="${value.image}"height: 25px; margin-left: 5px; max-width: none; width: 25px; 
85										viewBox="0 0 512 512" 
86									/> 
87								</span> 
88								<span class="learn-article-nav-text">${value.title}</span> 
89							</span> 
90 
91							<#if navigationMenuItems[productJSONObject.getString("title")].url == value.url> 
92								<span> 
93									<@clay["icon"] symbol="check" /> 
94								</span> 
95							</#if> 
96						</a> 
97					</li> 
98				</#list> 
99			</ul> 
100		</div> 
101	</#if> 
102 
103	<div class="learn-article-nav-content"> 
104		<#if parentJSONObject?has_content && parentJSONObject.getString("url")?has_content> 
105			<div class="learn-article-nav-item learn-article-nav-parent liferay-nav-item p-2"> 
106				<div class="mr-2"> 
107					<a 
108						href='${parentJSONObject.getString("url")}' 
109
110						<svg 
111							class="lexicon-icon lexicon-icon-angle-left" 
112							role="presentation" 
113							viewBox="0 0 512 512" 
114
115							<use xlink:href="/o/admin-theme/images/clay/icons.svg#angle-left"></use> 
116						</svg> 
117					</a> 
118				</div> 
119 
120				<span>${parentJSONObject.getString("title")}</span> 
121			</div> 
122		</#if> 
123 
124		<#if childrenJSONArray.length() gt 0> 
125			<ul class="m-0 p-2"> 
126				<#list 0..childrenJSONArray.length()-1 as i> 
127					<li class="learn-article-nav-item"> 
128						<a 
129							class='liferay-nav-item ${(navigationJSONObject.getJSONObject("self").url == childrenJSONArray.getJSONObject(i).url)?then("selected", "")}' 
130							href="${childrenJSONArray.getJSONObject(i).url}" 
131
132							<span>${childrenJSONArray.getJSONObject(i).getString("title")}</span> 
133						</a> 
134					</li> 
135				</#list> 
136			</ul> 
137		<#elseif siblingsJSONArray.length() gt 0> 
138			<ul class="m-0 p-2"> 
139				<#list 0..siblingsJSONArray.length()-1 as i> 
140					<li class="learn-article-nav-item"> 
141						<a 
142							class='liferay-nav-item ${(navigationJSONObject.getJSONObject("self").url == siblingsJSONArray.getJSONObject(i).url)?then("selected", "")}' 
143							href="${siblingsJSONArray.getJSONObject(i).url}" 
144
145							<span>${siblingsJSONArray.getJSONObject(i).getString("title")}</span> 
146						</a> 
147					</li> 
148				</#list> 
149			</ul> 
150		</#if> 
151	</div> 
152</div> 

Example: Removing Intermediate Journal Article Versions

These instructions and code samples demonstrate removing intermediate Journal Article versions. In the script console, you can remove unneeded object versions by executing Java or Groovy code.

Here are example steps for removing intermediate Journal Article versions:

  1. Decide how many of the latest versions to keep. You must keep the original version and the most recent version, but you may keep additional recent versions too. For example, you may want to keep the two latest versions or only the latest.

  2. Find a method for deleting the entity versions.

Liferay DXP App APIs and the com.liferay.portal.kernel API are available options for you to use.

If it's a [Service Builder](https://help.liferay.com/hc/en-us/articles/360030958811-Running-Service-Builder) entity, examine the `delete*` methods in the entity's `*LocalServiceUtil` class.

For example, this `deleteArticle` in `JournalArticleLocalServiceUtil` deletes a Journal Article version:

```java
deleteArticle(long groupId, java.lang.String articleId, double version,
    java.lang.String articleURL,
    com.liferay.portal.kernel.service.ServiceContext serviceContext)
```
  1. Aggregate the entity versions to delete and the information required to delete them.

    For example, get all the JournalArticle versions in range that match your removal criteria and associate their entity IDs and group IDs with them (the deleteArticle method shown above requires the entity ID and group ID).

    The entity object (e.g., JournalArticle) typically has a version field. JournalArticleResource has each JournalArticle’s article ID (the entity’s ID) and group ID. JournalArticleResource is the key to getting each JournalArticle, which can have multiple versions. Here are steps for identifying the JournalArticle versions to delete:

    Get all the JournalArticleResource objects.

    List<JournalArticleResource> journalArticleResources =
       JournalArticleLocalServiceUtil.getJournalArticleResources(start, end);
    

    Get each JournalArticle version’s workflow status via the JournalArticle object associated with each JournalArticleResource. Dynamic Query is an efficient way to get exactly the data you want from each object.

    for (JournalArticleResource
       journalArticeResource : journalArticleResources) {
    
       List<Double> journalArticlesVersionsToDelete =
             new ArrayList<Double>();
    
       DynamicQuery dq =
             DynamicQueryFactoryUtil.forClass(JournalArticle.class)
                .setProjection(ProjectionFactoryUtil.projectionList()
                   .add(ProjectionFactoryUtil.property("id"))
                   .add(ProjectionFactoryUtil.property("version"))
                   .add(ProjectionFactoryUtil.property("status")))
                .add(PropertyFactoryUtil.forName("groupId")
                   .eq(journalArticeResource.getGroupId()))
                .add(PropertyFactoryUtil.forName("articleId")
                   .eq(journalArticeResource.getArticleId()))
                .addOrder(OrderFactoryUtil.asc("version"));
    
       List<Object[]> result =
             JournalArticleLocalServiceUtil.dynamicQuery(dq);
    
       // See the next step for the sample code that goes here
    }
    

    For each JournalArticleResource (there’s one for each JournalArticle entity), build a list of intermediate versions in range of the first or latest versions you want to keep and whose status qualifies them for deletion. For example, you may want to delete intermediate article versions that are approved or expired (i.e., WorkflowConstants.STATUS_APPROVED or WorkflowConstants.STATUS_EXPIRED). The MIN_NUMBER_FIRST_VERSIONS_KEPT and MIN_NUMBER_LATEST_VERSIONS_KEPT variables mark the minimum and maximum number of first (oldest) and latest (newest) versions to keep.

    List<Double> journalArticlesVersionsToDelete =
       new ArrayList<Double>();
    
    for (int i=0; i < result.size(); i++) {
       long id = (long) result.get(i)[0];
       double version = (double) result.get(i)[1];
       int status = (int) result.get(i)[2];
    
       if ((status == WorkflowConstants.STATUS_APPROVED) || (status == WorkflowConstants.STATUS_EXPIRED) {
    
             if (i < MIN_NUMBER_FIRST_VERSIONS_KEPT) {
                continue;
             }
    
             if (i >= (result.size() -
                MIN_NUMBER_LATEST_VERSIONS_KEPT)) {
                continue;
             }
    
             journalArticlesVersionsToDelete.add(version);
       }
    }
    
    // See the next step for the sample code that goes here
    
  2. Lastly, delete each Journal Article matching the versions you aggregated.

    for (double version : journalArticlesVersionsToDelete) {
    {
       JournalArticleLocalServiceUtil.deleteArticle(journalArticeResource.getGroupId(),
          journalArticeResource.getArticleId(),
          journalArticlesVersionsToDelete(i), null, null);
    }
    

You can write similar code to remove intermediate versions of other entities. Once your code is ready, run it using either a sample module, or running it as a script using the script console.

Tip

Print the version (and any other information of interest) of each object you’re removing. You can also comment out the object deletion call and read the printout of versions to be removed as a test before committing to deleting them.