[x3d-public] Request for X3D encoding comment output from X3DPSAIL

John Carlson yottzumm at gmail.com
Mon Jan 5 12:18:04 PST 2026


Clueless on this stylesheet.  Beyond me!  The Java below makes more sense
to me!  Now my thought is to replace CDATA Sections inside comments. Argh!

<xsl:stylesheet version="2.0" xmlns:xsl="
http://www.w3.org/1999/XSL/Transform">

<!-- Identity template: copy everything as-is -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>

<!-- Handle comments -->
<xsl:template match="comment()">
<xsl:variable name="normalized">
<xsl:call-template name="normalize-tag-newlines">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:variable>

<!-- Split by remaining newlines -->
<xsl:for-each select="tokenize($normalized, '\n')">
<xsl:if test="normalize-space(.) != ''">
<xsl:comment>
<xsl:value-of select="normalize-space(.)"/>
</xsl:comment>
</xsl:if>
</xsl:for-each>
</xsl:template>

<!-- Normalize newlines within tags -->
<xsl:template name="normalize-tag-newlines">
<xsl:param name="text"/>

<!-- First normalize start tags (including self-closing tags) -->
<xsl:variable name="step1">
<xsl:analyze-string select="$text" regex="<([^/>][^>]*)>"
flags="s">
<xsl:matching-substring>
<xsl:text><</xsl:text>
<xsl:value-of select="replace(regex-group(1), '\s*\n\s*', ' ')"/>
<xsl:text>></xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>

<!-- Then normalize end tags -->
<xsl:analyze-string select="$step1" regex="<(/[^>]*)>">
<xsl:matching-substring>
<xsl:text><</xsl:text>
<xsl:value-of select="replace(regex-group(1), '\s*\n\s*', ' ')"/>
<xsl:text>></xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>

</xsl:stylesheet>


On Mon, Jan 5, 2026 at 2:09 PM John Carlson <yottzumm at gmail.com> wrote:

> Okay, heres one that replaces newlines with spaces between < and > inside
> comments and add comments for newlines in comments elsewhere.  Stylesheet
> is next!
>
>>
> import org.xml.sax.SAXException;
> import org.xml.sax.ext.DefaultHandler2;
> import java.io.IOException;
> import java.io.Writer;
> import java.util.regex.Pattern;
> import java.util.regex.Matcher;
>
> public class CommentNormalizingHandler extends DefaultHandler2 {
> private Writer writer;
>
> public CommentNormalizingHandler(Writer writer) {
> this.writer = writer;
> }
>
> @Override
> public void comment(char[] ch, int start, int length) throws SAXException {
> try {
> String commentText = new String(ch, start, length);
>
> // Check if comment contains XML tag-like structures with newlines
> if (containsTagWithNewlines(commentText)) {
> // Normalize newlines within tags but keep multi-line structure outside
> tags
> String normalized = normalizeTagNewlines(commentText);
>
> // Now split by remaining newlines (those outside tags)
> String[] lines = normalized.split("\\n");
> for (String line : lines) {
> String trimmed = line.trim();
> if (!trimmed.isEmpty()) {
> writer.write("<!--");
> writer.write(trimmed);
> writer.write("-->");
> }
> }
> } else {
> // No tags with newlines - safe to split normally
> String[] lines = commentText.split("\\n");
> for (String line : lines) {
> String trimmed = line.trim();
> if (!trimmed.isEmpty()) {
> writer.write("<!--");
> writer.write(trimmed);
> writer.write("-->");
> }
> }
> }
> } catch (IOException e) {
> throw new SAXException("Error writing comment", e);
> }
> }
>
> private boolean containsTagWithNewlines(String text) {
> // Check for start tags with newlines: <tag...newline...>
> Pattern startTagPattern = Pattern.compile("<[^/>][^>]*\\n[^>]*>",
> Pattern.DOTALL);
> if (startTagPattern.matcher(text).find()) {
> return true;
> }
>
> // Check for end tags with newlines: </tag...newline...>
> Pattern endTagPattern = Pattern.compile("</[^>]*\\n[^>]*>");
> if (endTagPattern.matcher(text).find()) {
> return true;
> }
>
> return false;
> }
>
> private String normalizeTagNewlines(String text) {
> // Replace newlines within start tags (between < and >)
> Pattern startTagPattern = Pattern.compile("<([^/>][^>]*)>",
> Pattern.DOTALL);
> Matcher startMatcher = startTagPattern.matcher(text);
> StringBuffer sb = new StringBuffer();
>
> while (startMatcher.find()) {
> String tagContent = startMatcher.group(1);
> String normalized = tagContent.replaceAll("\\s*\\n\\s*", " ");
> startMatcher.appendReplacement(sb, "<" +
> Matcher.quoteReplacement(normalized) + ">");
> }
> startMatcher.appendTail(sb);
>
> // Replace newlines within end tags
> Pattern endTagPattern = Pattern.compile("<(/[^>]*)>");
> Matcher endMatcher = endTagPattern.matcher(sb.toString());
> StringBuffer sb2 = new StringBuffer();
>
> while (endMatcher.find()) {
> String tagContent = endMatcher.group(1);
> String normalized = tagContent.replaceAll("\\s*\\n\\s*", " ");
> endMatcher.appendReplacement(sb2, "<" +
> Matcher.quoteReplacement(normalized) + ">");
> }
> endMatcher.appendTail(sb2);
>
> return sb2.toString();
>
> }
>
> @Override
> public void startElement(String uri, String localName, String qName,
> org.xml.sax.Attributes attributes) throws SAXException {
> try {
> writer.write("<");
> writer.write(qName);
>
> for (int i = 0; i < attributes.getLength(); i++) {
> writer.write(" ");
> writer.write(attributes.getQName(i));
> writer.write("='");
> writer.write(escapeXml(attributes.getValue(i)));
> writer.write("'");
> }
>
> writer.write(">");
> } catch (IOException e) {
> throw new SAXException("Error writing start element", e);
> }
> }
>
> @Override
> public void endElement(String uri, String localName, String qName) throws
> SAXException {
> try {
> writer.write("</");
> writer.write(qName);
> writer.write(">");
> } catch (IOException e) {
> throw new SAXException("Error writing end element", e);
> }
> }
>
> @Override
> public void characters(char[] ch, int start, int length) throws
> SAXException {
> try {
> writer.write(escapeXml(new String(ch, start, length)));
> } catch (IOException e) {
> throw new SAXException("Error writing characters", e);
> }
> }
>
> @Override
> public void startDocument() throws SAXException {
> try {
> writer.write("<?xml version='1.0' encoding='UTF-8'?>");
> } catch (IOException e) {
> throw new SAXException("Error writing start document", e);
> }
> }
>
> @Override
> public void processingInstruction(String target, String data) throws
> SAXException {
> try {
> writer.write("<?");
> writer.write(target);
> if (data != null && !data.isEmpty()) {
> writer.write(" ");
> writer.write(data);
> }
> writer.write("?>");
> } catch (IOException e) {
> throw new SAXException("Error writing processing instruction", e);
> }
> }
>
> private String escapeXml(String text) {
> return text.replace("&", "&")
> .replace("<", "<")
> .replace(">", ">")
> .replace("'", "'")
> .replace("\"", """);
> }
> }
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20260105/d4696047/attachment-0001.html>


More information about the x3d-public mailing list