Skip to content

fix: parse doctype correctly#2798

Merged
kacperzolkiewski merged 2 commits into
software-mansion:mainfrom
fedibtc:ol/fix-doctype
Oct 15, 2025
Merged

fix: parse doctype correctly#2798
kacperzolkiewski merged 2 commits into
software-mansion:mainfrom
fedibtc:ol/fix-doctype

Conversation

@otech47
Copy link
Copy Markdown
Contributor

@otech47 otech47 commented Oct 13, 2025

Summary

  • fixes Parsing breaks when comments exists before <!DOCTYPE.. in svg file. #2532
  • I encountered this bug trying to render an <SvgUri> component with a remote uri
  • DOCTYPE declarations (e.g., ) are metadata that should not be parsed as content and affect the SVG anyway. There is logic to account for this, however if encountered after a comment and before the opening tag, neutral() would collect the DOCTYPE text and try to push it to children before the root element exists that instantiates children to a non-null array you can push to (causing "Cannot read property 'push' of null")

Test Plan

Call the parse function with this SVG code without this fix and you will see the error. Or render an <SvgUri> component with this remote URI: https://www.svgrepo.com/show/4733/samples.svg

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" 
         viewBox="0 0 297.5 297.5" xml:space="preserve">
<g id="XMLID_40_">
        <g>
                <path style="fill:#ACBFC7;" d="M277.71,158.52v85.7H19.79v-85.7h6.53v40.54c0,16.98,13.81,30.78,30.78,30.78
                        s30.78-13.8,30.78-30.78v-40.54h30.09v40.54c0,16.98,13.81,30.78,30.78,30.78c16.98,0,30.78-13.8,30.78-30.78v-40.54h30.1v40.54
                        c0,16.98,13.8,30.78,30.78,30.78c16.97,0,30.78-13.8,30.78-30.78v-40.54H277.71z"/>
                <rect x="218.66" y="53.28" style="fill:#CDD9DD;" width="43.49" height="10.53"/>
                <rect x="229.17" y="83.35" style="fill:#CDD9DD;" width="22.48" height="23.92"/>
                <rect x="137.51" y="83.35" style="fill:#CDD9DD;" width="22.48" height="23.92"/>
                <rect x="127.01" y="53.28" style="fill:#CDD9DD;" width="43.49" height="10.53"/>
                <rect x="35.35" y="53.28" style="fill:#CDD9DD;" width="43.49" height="10.53"/>
                <rect x="45.86" y="83.35" style="fill:#CDD9DD;" width="22.48" height="23.92"/>
                <path style="fill:#FF4855;" d="M251.65,126.81v72.25c0,6.2-5.05,11.24-11.24,11.24c-6.2,0-11.24-5.04-11.24-11.24v-72.25H251.65z"
                        />
                <path style="fill:#D61616;" d="M68.34,126.81v72.25c0,6.2-5.04,11.24-11.24,11.24s-11.24-5.04-11.24-11.24v-72.25H68.34z"/>
                <path style="fill:#FFD63F;" d="M159.99,126.81v72.25c0,6.2-5.04,11.24-11.24,11.24s-11.24-5.04-11.24-11.24v-72.25H159.99z"/>
                <path d="M297.25,148.75v105.24c0,5.4-4.37,9.77-9.77,9.77H10.02c-5.39,0-9.77-4.37-9.77-9.77V148.75c0-5.4,4.38-9.77,9.77-9.77
                        h16.3V83.35h-0.74c-5.39,0-9.77-4.38-9.77-9.77V43.51c0-5.4,4.38-9.77,9.77-9.77h63.03c5.4,0,9.77,4.37,9.77,9.77v30.07
                        c0,5.39-4.37,9.77-9.77,9.77h-0.73v55.63h30.09V83.35h-0.73c-5.4,0-9.77-4.38-9.77-9.77V43.51c0-5.4,4.37-9.77,9.77-9.77h63.03
                        c5.39,0,9.77,4.37,9.77,9.77v30.07c0,5.39-4.38,9.77-9.77,9.77h-0.74v55.63h30.1V83.35h-0.74c-5.39,0-9.77-4.38-9.77-9.77V43.51
                        c0-5.4,4.38-9.77,9.77-9.77h63.03c5.4,0,9.77,4.37,9.77,9.77v30.07c0,5.39-4.37,9.77-9.77,9.77h-0.73v55.63h16.29
                        C292.88,138.98,297.25,143.35,297.25,148.75z M277.71,244.22v-85.7h-6.52v40.54c0,16.98-13.81,30.78-30.78,30.78
                        c-16.98,0-30.78-13.8-30.78-30.78v-40.54h-30.1v40.54c0,16.98-13.8,30.78-30.78,30.78c-16.97,0-30.78-13.8-30.78-30.78v-40.54
                        H87.88v40.54c0,16.98-13.81,30.78-30.78,30.78s-30.78-13.8-30.78-30.78v-40.54h-6.53v85.7H277.71z M262.15,63.81V53.28h-43.49
                        v10.53H262.15z M251.65,199.06v-72.25h-22.48v72.25c0,6.2,5.04,11.24,11.24,11.24C246.6,210.3,251.65,205.26,251.65,199.06z
                         M251.65,107.27V83.35h-22.48v23.92H251.65z M170.5,63.81V53.28h-43.49v10.53H170.5z M159.99,199.06v-72.25h-22.48v72.25
                        c0,6.2,5.04,11.24,11.24,11.24S159.99,205.26,159.99,199.06z M159.99,107.27V83.35h-22.48v23.92H159.99z M78.84,63.81V53.28H35.35
                        v10.53H78.84z M68.34,199.06v-72.25H45.86v72.25c0,6.2,5.04,11.24,11.24,11.24S68.34,205.26,68.34,199.06z M68.34,107.27V83.35
                        H45.86v23.92H68.34z"/>
        </g>
        <g>
        </g>
</g>
</svg>

You can see this debug output to compare the results before and after the fix

before

 DEBUG  xml parse {"length": 3162, "source": "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">
<svg version=\"1.1\" id=\"Capa_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" 
         viewBox=\"0 0 297.5 297.5\" xml:space=\"preserve\">
<g id=\"XMLID_40_\">
        <g>
                <path style=\"fill:#ACBFC7;\" d=\"M277.71,158.52v85.7H19.79v-85.7h6.53v40.54c0,16.98,13.81,30.78,30.78,30.78
                        s30.78-13.8,30.78-30.78v-40.54h30.09v40.54c0,16.98,13.81,30.78,30.78,30.78c16.98,0,30.78-13.8,30.78-30.78v-40.54h30.1v40.54
                        c0,16.98,13.8,30.78,30.78,30.78c16.97,0,30.78-13.8,30.78-30.78v-40.54H277.71z\"/>
                <rect x=\"218.66\" y=\"53.28\" style=\"fill:#CDD9DD;\" width=\"43.49\" height=\"10.53\"/>
                <rect x=\"229.17\" y=\"83.35\" style=\"fill:#CDD9DD;\" width=\"22.48\" height=\"23.92\"/>
                <rect x=\"137.51\" y=\"83.35\" style=\"fill:#CDD9DD;\" width=\"22.48\" height=\"23.92\"/>
                <rect x=\"127.01\" y=\"53.28\" style=\"fill:#CDD9DD;\" width=\"43.49\" height=\"10.53\"/>
                <rect x=\"35.35\" y=\"53.28\" style=\"fill:#CDD9DD;\" width=\"43.49\" height=\"10.53\"/>
                <rect x=\"45.86\" y=\"83.35\" style=\"fill:#CDD9DD;\" width=\"22.48\" height=\"23.92\"/>
                <path style=\"fill:#FF4855;\" d=\"M251.65,126.81v72.25c0,6.2-5.05,11.24-11.24,11.24c-6.2,0-11.24-5.04-11.24-11.24v-72.25H251.65z\"
                        />
                <path style=\"fill:#D61616;\" d=\"M68.34,126.81v72.25c0,6.2-5.04,11.24-11.24,11.24s-11.24-5.04-11.24-11.24v-72.25H68.34z\"/>
                <path style=\"fill:#FFD63F;\" d=\"M159.99,126.81v72.25c0,6.2-5.04,11.24-11.24,11.24s-11.24-5.04-11.24-11.24v-72.25H159.99z\"/>
                <path d=\"M297.25,148.75v105.24c0,5.4-4.37,9.77-9.77,9.77H10.02c-5.39,0-9.77-4.37-9.77-9.77V148.75c0-5.4,4.38-9.77,9.77-9.77
                        h16.3V83.35h-0.74c-5.39,0-9.77-4.38-9.77-9.77V43.51c0-5.4,4.38-9.77,9.77-9.77h63.03c5.4,0,9.77,4.37,9.77,9.77v30.07
                        c0,5.39-4.37,9.77-9.77,9.77h-0.73v55.63h30.09V83.35h-0.73c-5.4,0-9.77-4.38-9.77-9.77V43.51c0-5.4,4.37-9.77,9.77-9.77h63.03
                        c5.39,0,9.77,4.37,9.77,9.77v30.07c0,5.39-4.38,9.77-9.77,9.77h-0.74v55.63h30.1V83.35h-0.74c-5.39,0-9.77-4.38-9.77-9.77V43.51
                        c0-5.4,4.38-9.77,9.77-9.77h63.03c5.4,0,9.77,4.37,9.77,9.77v30.07c0,5.39-4.37,9.77-9.77,9.77h-0.73v55.63h16.29
                        C292.88,138.98,297.25,143.35,297.25,148.75z M277.71,244.22v-85.7h-6.52v40.54c0,16.98-13.81,30.78-30.78,30.78
                        c-16.98,0-30.78-13.8-30.78-30.78v-40.54h-30.1v40.54c0,16.98-13.8,30.78-30.78,30.78c-16.97,0-30.78-13.8-30.78-30.78v-40.54
                        H87.88v40.54c0,16.98-13.81,30.78-30.78,30.78s-30.78-13.8-30.78-30.78v-40.54h-6.53v85.7H277.71z M262.15,63.81V53.28h-43.49
                        v10.53H262.15z M251.65,199.06v-72.25h-22.48v72.25c0,6.2,5.04,11.24,11.24,11.24C246.6,210.3,251.65,205.26,251.65,199.06z
                         M251.65,107.27V83.35h-22.48v23.92H251.65z M170.5,63.81V53.28h-43.49v10.53H170.5z M159.99,199.06v-72.25h-22.48v72.25
                        c0,6.2,5.04,11.24,11.24,11.24S159.99,205.26,159.99,199.06z M159.99,107.27V83.35h-22.48v23.92H159.99z M78.84,63.81V53.28H35.35
                        v10.53H78.84z M68.34,199.06v-72.25H45.86v72.25c0,6.2,5.04,11.24,11.24,11.24S68.34,205.26,68.34,199.06z M68.34,107.27V83.35
                        H45.86v23.92H68.34z\"/>
        </g>
        <g>
        </g>
</g>
</svg>"}
 DEBUG  xml parse neutral {"children": null, "text": "", "textType": "string"}
 DEBUG  xml parse neutral {"children": null, "text": "
", "textType": "string"}
 DEBUG  xml parse neutral {"children": null, "text": "DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">
", "textType": "string"}
 DEBUG  SvgXml error [TypeError: Cannot read property 'push' of null]
 ERROR  [TypeError: Cannot read property 'push' of null] [Component Stack]

AFTER

 DEBUG  xml parse {"length": 989, "source": "<svg
        
        
        viewBox=\"0 0 350 120\"
        fill=\"none\"
        xmlns=\"http://www.w3.org/2000/svg\"
        preserveAspectRatio=\"none\">
            
<rect width=\"350\" height=\"120\" fill=\"#D3D4DB\"/>
<rect width=\"350\" height=\"120\" fill=\"url(#paint0_radial_4232_39591)\"/>
<rect width=\"350\" height=\"120\" fill=\"url(#paint1_radial_4232_39591)\"/>
<defs>
    <radialGradient id=\"paint0_radial_4232_39591\" cx=\"0\" cy=\"0\" r=\"1\" gradientTransform=\"matrix(458.538 142.353 -289.724 353.12 -5.73771 80.2941)\" gradientUnits=\"userSpaceOnUse\">
        <stop stop-color=\"#FFF9DE\"/>
        <stop offset=\"1\" stop-color=\"white\" stop-opacity=\"0\"/>
    </radialGradient>
    <radialGradient id=\"paint1_radial_4232_39591\" cx=\"0\" cy=\"0\" r=\"1\" gradientTransform=\"matrix(-47.8142 152.353 -257.651 -30.5962 279.713 -5.58825)\" gradientUnits=\"userSpaceOnUse\">
        <stop stop-color=\"#B6EAFF\"/>
        <stop offset=\"1\" stop-color=\"white\" stop-opacity=\"0.04\"/>
    </radialGradient>
</defs>

    </svg>"}
 DEBUG  xml parse neutral {"children": null, "text": "", "textType": "string"}
 DEBUG  xml parse neutral {"children": [], "text": "
            
", "textType": "string"}
 DEBUG  xml parse neutral {"children": [{"Tag": [Function Rect], "children": [Array], "parent": [Object], "props": [Object], "tag": "rect"}], "text": "
", "textType": "string"}

Checklist

  • I have tested this on a device and a simulator
  • I added documentation in README.md
  • I updated the typed files (typescript)
  • I added a test for the API in the __tests__ folder

- DOCTYPE declarations (e.g., <!DOCTYPE svg PUBLIC...>) are metadata that should be skipped, not parsed as content. Without this fix, neutral() would collect the DOCTYPE text and try to push it to children before the root element exists (causing "Cannot read property 'push' of null")
@kacperzolkiewski
Copy link
Copy Markdown
Collaborator

Thanks for the fix!
I tested it and the bug is solved with those changes 👏

Comment thread src/xml.tsx Outdated
Co-authored-by: Kacper Żółkiewski <74975508+kacperzolkiewski@users.noreply.github.com>
Copy link
Copy Markdown
Member

@jakex7 jakex7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

@kacperzolkiewski kacperzolkiewski merged commit 5f38648 into software-mansion:main Oct 15, 2025
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parsing breaks when comments exists before <!DOCTYPE.. in svg file.

3 participants