Skip to content

Commit ea52ccb

Browse files
author
Steve Ramage
committed
Checkpoint
1 parent ea7864f commit ea52ccb

File tree

2 files changed

+91
-15
lines changed

2 files changed

+91
-15
lines changed

buildSrc/src/main/groovy/GenerateDataFromManPages.groovy

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import org.w3c.dom.Document
88
import org.w3c.dom.Node
99
import org.w3c.dom.NodeList
1010
import org.w3c.dom.ls.DOMImplementationLS
11+
import org.w3c.dom.ls.LSParser
1112
import org.w3c.dom.ls.LSSerializer
13+
import org.xml.sax.InputSource
1214

1315
import javax.xml.parsers.DocumentBuilder
1416
import javax.xml.parsers.DocumentBuilderFactory
@@ -21,6 +23,7 @@ import javax.xml.xpath.XPath
2123
import javax.xml.xpath.XPathConstants
2224
import javax.xml.xpath.XPathFactory
2325
import java.util.regex.Matcher
26+
import java.util.regex.Pattern
2427

2528
/**
2629
* This task scans the systemd source code man pages to extract the set of available options as well as (eventually) documentation.
@@ -231,6 +234,7 @@ class GenerateDataFromManPages extends DefaultTask {
231234
'[QuickFairQueueing] Section Options': ['QuickFairQueueing'],
232235
'[QuickFairQueueingClass] Section Options': ['QuickFairQueueingClass'],
233236
'[BridgeVLAN] Section Options': ['BridgeVLAN'],
237+
234238
]
235239
]
236240
],
@@ -254,20 +258,6 @@ class GenerateDataFromManPages extends DefaultTask {
254258
@Internal
255259
final DocumentBuilderFactory dbf
256260

257-
public GenerateDataFromManPages() {
258-
xpath = XPathFactory.newInstance().newXPath()
259-
260-
dbf = DocumentBuilderFactory.newInstance()
261-
dbf.setXIncludeAware(true)
262-
dbf.setValidating(false)
263-
dbf.setExpandEntityReferences(false)
264-
265-
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
266-
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
267-
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
268-
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
269-
}
270-
271261

272262
@TaskAction
273263
void start() {
@@ -418,6 +408,21 @@ class GenerateDataFromManPages extends DefaultTask {
418408
[name, value]
419409
}
420410

411+
public GenerateDataFromManPages() {
412+
xpath = XPathFactory.newInstance().newXPath()
413+
414+
dbf = DocumentBuilderFactory.newInstance()
415+
dbf.setXIncludeAware(true)
416+
//dbf.setNamespaceAware(true)
417+
dbf.setValidating(false)
418+
dbf.setExpandEntityReferences(false)
419+
420+
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
421+
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)
422+
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false)
423+
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false)
424+
}
425+
421426
/**
422427
* Generates individual HTML files for use as inline documentation
423428
*
@@ -429,14 +434,66 @@ class GenerateDataFromManPages extends DefaultTask {
429434
private generateDocumentationHtmlFromManPages(String fileType, File sourceFile) {
430435
DocumentBuilder builder = dbf.newDocumentBuilder()
431436

432-
Document document = builder.parse(sourceFile)
437+
String xmlContent = sourceFile.text
438+
439+
440+
// I spent an hour with ChatGPT trying to get
441+
// Xincludes to work properly (without spending 6 hours to understand them).
442+
// Couldn't get it to work, due to Java not liking things like includes with no href, for local references.
443+
// 💣 Step 1: Replace XInclude elements using regex
444+
xmlContent = processXIncludesWithRegex(xmlContent, sourceFile.parentFile)
445+
446+
447+
File outputDir = project.layout.buildDirectory.dir("tmp/rendered-xincludes").get().asFile
448+
if (!outputDir.exists()) {
449+
outputDir.mkdirs()
450+
}
451+
452+
File outputFile = new File(outputDir, sourceFile.getName())
453+
outputFile.text = xmlContent // Save to file
454+
455+
Document document = builder.parse(outputFile)
433456
Transformer transformer = getXsltTransformer()
434457

435458
String xsltOutput = transformDocument(document, transformer)
436459

437460
segmentParametersIntoFiles(fileType, sourceFile.getName(), xsltOutput)
438461
}
439462

463+
private String processXIncludesWithRegex(String xmlContent, File baseDir) {
464+
// 🔥 Regex to match <xi:include href="some.xml" xpointer="some-id"/> (xpointer is optional)
465+
def includePattern = /<xi:include\s+href="([^"]+)"(?:\s+xpointer="([^"]+)")?\s*\/>/
466+
467+
468+
return xmlContent.replaceAll(includePattern) { match, href, xpointer ->
469+
File includedFile = new File(baseDir, href)
470+
471+
if (!includedFile.exists()) {
472+
println "⚠️ WARNING: Included file '${includedFile.absolutePath}' not found!"
473+
return "<!-- Failed to include: $href -->"
474+
}
475+
476+
String includedContent = includedFile.text
477+
478+
if (xpointer) {
479+
// Extract only the element with the specified ID
480+
481+
//includedContent = extractById(includedContent, xpointer) ?: "<!-- Failed to find xpointer '$xpointer' in $href -->"
482+
483+
def xmlContent2 = includedContent
484+
def idPattern = Pattern.compile(/<([a-zA-Z0-9:_-]+)\s+[^>]*id=["']$xpointer["'][^>]*>(.*?)<\/\1>/, Pattern.DOTALL)
485+
def matcher = xmlContent2 =~ idPattern
486+
487+
def resContent = matcher.find() ? matcher.group(0) : null
488+
489+
includedContent = "<!--xi:include='$href' xpointer='$xpointer'-->" + resContent + "<!-- /xi:include='$href' xpointer='$xpointer' -->"
490+
}
491+
492+
return includedContent
493+
}
494+
}
495+
496+
440497
/**
441498
* Transforms the supplied document with the supplied transformer
442499
* @param document - XML Document to transform
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<xsl:stylesheet version="1.0"
3+
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
4+
xmlns:xi="http://www.w3.org/2001/XInclude">
5+
6+
<!-- Identity template: Copies everything as-is -->
7+
<xsl:template match="@* | node()">
8+
<xsl:copy>
9+
<xsl:apply-templates select="@* | node()"/>
10+
</xsl:copy>
11+
</xsl:template>
12+
13+
<!-- Process XInclude -->
14+
<xsl:template match="xi:include">
15+
<xsl:variable name="file" select="@href"/>
16+
<xsl:apply-templates select="document($file)/*"/>
17+
</xsl:template>
18+
19+
</xsl:stylesheet>

0 commit comments

Comments
 (0)