[ 
https://issues.apache.org/jira/browse/GROOVY-9698?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17181218#comment-17181218
 ] 

Rachel commented on GROOVY-9698:
--------------------------------

By the way it looks like StreamingMarkupBuilder.groovy has the same bug at line 
174, but as I haven't actually needed that one to work yet, I haven't done the 
test-writing work.

> StreamingSAXBuilder repeats xmlns declarations on inner elements
> ----------------------------------------------------------------
>
>                 Key: GROOVY-9698
>                 URL: https://issues.apache.org/jira/browse/GROOVY-9698
>             Project: Groovy
>          Issue Type: Bug
>          Components: XML Processing
>    Affects Versions: 3.0.5
>         Environment: Encounted on MacOS Catalina, which I don't believe is 
> relevant. Using AdoptOpenJDK 14 throughout, which should also not be relevant.
>            Reporter: Rachel
>            Priority: Minor
>              Labels: patch, xml
>         Attachments: saxbuilder.diff
>
>   Original Estimate: 5m
>  Remaining Estimate: 5m
>
> The bug is in StreamingSAXBuilder.groovy line 81 (in 3.0.5 and master as of 
> now), in tagClosure, where the line:
> {{pendingStack.add pendingNamespaces.clone()}}
> should read:
> {{pendingStack.push pendingNamespaces.clone()}}
> ... to match the pendingStack.pop() happening a few lines later, after 
> processing the tag body. So the current pendingNamespaces map is being added 
> to the end of the stack, and then popped off the beginning. Which means the 
> _wrong_ map is being popped off, and can result in the next element being 
> given those namespaces as if it was declaring them anew.
> I modified the testDefaultSerializationNamespaces in 
> StreamingSAXBuilderTest.groovy to add two inner elements to demonstrate this, 
> so the test now had:
> {{def doc = new StreamingSAXBuilder().bind {}}}}
>  {{ {{    mkp.declareNamespace("" : "uri:urn1")}}}}
>  {{ {{    mkp.declareNamespace("x" : "uri:urn2")}}}}
>  {{ {{    outer {}}}}
>  {{ {{        'x:inner'('hello')}}}}
>  {{ {{        'x:inner'('hello again')}}}}
>  \{{     }}}
>  {{}}}
>  \{{ def expected = '<outer xmlns="uri:urn1" 
> xmlns:x="uri:urn2"><x:inner>hello</x:inner><x:inner>hello 
> again</x:inner></outer>'}}
> (edit: I've tried to format this code block properly, it insists on messing 
> it up.)
> The test still passes at this point because the XmlUnit/Diff implementations 
> elide the extra namespace declarations away. If you actually print the 
> resulting XML you can see the problem:
> {{<outer xmlns="uri:urn1" xmlns:x="uri:urn2"><x:inner>hello</x:inner><x:inner 
> xmlns="uri:urn1" xmlns:x="uri:urn2">hello again</x:inner></outer>}}
> I think this will result in larger problems with more complicated XMLs being 
> built.
> So I added an assertion to compare the output string with the expected value, 
> to reveal the problem. This necessitated (for now) an annoying change in 
> StreamingSAXBuilder to sort the pending namespaces map before processing 
> them, so they would appear in a predictable order. (BaseMarkupBuilder uses a 
> HashMap - not sure what permanent solution you'd prefer there, seeing as it's 
> just for the string-comparison test to run. It might be to write a separate 
> test that only tests with one added namespace, for instance.)
>  
> Attachment is a diff based on current-master to include this test in 
> StreamingSAXBuilderTest.groovy and the changes in StreamingSAXBuilder.groovy: 
> the sort() which is only there for the test, and changing the 
> pendingStack.add to a pendingStack.push, which fixes the problem, so the test 
> passes. Revert it to pendingStack.add to see it fail.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to