@@ -2399,6 +2399,7 @@ typedef struct {
2399
2399
2400
2400
PyObject * this ; /* current node */
2401
2401
PyObject * last ; /* most recently created node */
2402
+ PyObject * last_for_tail ; /* most recently created node that takes a tail */
2402
2403
2403
2404
PyObject * data ; /* data collector (string or list), or NULL */
2404
2405
@@ -2530,6 +2531,7 @@ treebuilder_gc_traverse(TreeBuilderObject *self, visitproc visit, void *arg)
2530
2531
Py_VISIT (self -> root );
2531
2532
Py_VISIT (self -> this );
2532
2533
Py_VISIT (self -> last );
2534
+ Py_VISIT (self -> last_for_tail );
2533
2535
Py_VISIT (self -> data );
2534
2536
Py_VISIT (self -> stack );
2535
2537
Py_VISIT (self -> pi_factory );
@@ -2551,6 +2553,7 @@ treebuilder_gc_clear(TreeBuilderObject *self)
2551
2553
Py_CLEAR (self -> stack );
2552
2554
Py_CLEAR (self -> data );
2553
2555
Py_CLEAR (self -> last );
2556
+ Py_CLEAR (self -> last_for_tail );
2554
2557
Py_CLEAR (self -> this );
2555
2558
Py_CLEAR (self -> pi_factory );
2556
2559
Py_CLEAR (self -> comment_factory );
@@ -2622,21 +2625,48 @@ _elementtree__set_factories_impl(PyObject *module, PyObject *comment_factory,
2622
2625
}
2623
2626
2624
2627
static int
2625
- treebuilder_set_element_text_or_tail (PyObject * element , PyObject * * data ,
2626
- PyObject * * dest , _Py_Identifier * name )
2628
+ treebuilder_extend_element_text_or_tail (PyObject * element , PyObject * * data ,
2629
+ PyObject * * dest , _Py_Identifier * name )
2627
2630
{
2631
+ /* Fast paths for the "almost always" cases. */
2628
2632
if (Element_CheckExact (element )) {
2629
- PyObject * tmp = JOIN_OBJ (* dest );
2630
- * dest = JOIN_SET (* data , PyList_CheckExact (* data ));
2631
- * data = NULL ;
2632
- Py_DECREF (tmp );
2633
- return 0 ;
2633
+ PyObject * dest_obj = JOIN_OBJ (* dest );
2634
+ if (dest_obj == Py_None ) {
2635
+ * dest = JOIN_SET (* data , PyList_CheckExact (* data ));
2636
+ * data = NULL ;
2637
+ Py_DECREF (dest_obj );
2638
+ return 0 ;
2639
+ }
2640
+ else if (JOIN_GET (* dest )) {
2641
+ if (PyList_SetSlice (dest_obj , PY_SSIZE_T_MAX , PY_SSIZE_T_MAX , * data ) < 0 ) {
2642
+ return -1 ;
2643
+ }
2644
+ Py_CLEAR (* data );
2645
+ return 0 ;
2646
+ }
2634
2647
}
2635
- else {
2636
- PyObject * joined = list_join (* data );
2648
+
2649
+ /* Fallback for the non-Element / non-trivial cases. */
2650
+ {
2637
2651
int r ;
2638
- if (joined == NULL )
2652
+ PyObject * joined , * previous = _PyObject_GetAttrId (element , name );
2653
+ if (!previous )
2639
2654
return -1 ;
2655
+ joined = list_join (* data );
2656
+ if (!joined ) {
2657
+ Py_DECREF (previous );
2658
+ return -1 ;
2659
+ }
2660
+ if (previous != Py_None ) {
2661
+ PyObject * tmp = PyNumber_Add (previous , joined );
2662
+ Py_DECREF (joined );
2663
+ if (!tmp ) {
2664
+ Py_DECREF (previous );
2665
+ return -1 ;
2666
+ }
2667
+ joined = tmp ;
2668
+ }
2669
+
2640
2670
r = _PyObject_SetAttrId (element , name , joined );
2641
2671
Py_DECREF (joined );
2642
2672
if (r < 0 )
@@ -2649,21 +2679,21 @@ treebuilder_set_element_text_or_tail(PyObject *element, PyObject **data,
2649
2679
LOCAL (int )
2650
2680
treebuilder_flush_data (TreeBuilderObject * self )
2651
2681
{
2652
- PyObject * element = self -> last ;
2653
-
2654
2682
if (!self -> data ) {
2655
2683
return 0 ;
2656
2684
}
2657
2685
2658
- if (self -> this == element ) {
2686
+ if (!self -> last_for_tail ) {
2687
+ PyObject * element = self -> last ;
2659
2688
_Py_IDENTIFIER (text );
2660
- return treebuilder_set_element_text_or_tail (
2689
+ return treebuilder_extend_element_text_or_tail (
2661
2690
element , & self -> data ,
2662
2691
& ((ElementObject * ) element )-> text , & PyId_text );
2663
2692
}
2664
2693
else {
2694
+ PyObject * element = self -> last_for_tail ;
2665
2695
_Py_IDENTIFIER (tail );
2666
- return treebuilder_set_element_text_or_tail (
2696
+ return treebuilder_extend_element_text_or_tail (
2667
2697
element , & self -> data ,
2668
2698
& ((ElementObject * ) element )-> tail , & PyId_tail );
2669
2699
}
@@ -2739,6 +2769,7 @@ treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag,
2739
2769
}
2740
2770
2741
2771
this = self -> this ;
2772
+ Py_CLEAR (self -> last_for_tail );
2742
2773
2743
2774
if (this != Py_None ) {
2744
2775
if (treebuilder_add_subelement (this , node ) < 0 )
@@ -2836,6 +2867,8 @@ treebuilder_handle_end(TreeBuilderObject* self, PyObject* tag)
2836
2867
2837
2868
item = self -> last ;
2838
2869
self -> last = self -> this ;
2870
+ Py_INCREF (self -> last );
2871
+ Py_XSETREF (self -> last_for_tail , self -> last );
2839
2872
self -> index -- ;
2840
2873
self -> this = PyList_GET_ITEM (self -> stack , self -> index );
2841
2874
Py_INCREF (self -> this );
@@ -2867,6 +2900,8 @@ treebuilder_handle_comment(TreeBuilderObject* self, PyObject* text)
2867
2900
if (self -> insert_comments && this != Py_None ) {
2868
2901
if (treebuilder_add_subelement (this , comment ) < 0 )
2869
2902
goto error ;
2903
+ Py_INCREF (comment );
2904
+ Py_XSETREF (self -> last_for_tail , comment );
2870
2905
}
2871
2906
} else {
2872
2907
Py_INCREF (text );
@@ -2906,6 +2941,8 @@ treebuilder_handle_pi(TreeBuilderObject* self, PyObject* target, PyObject* text)
2906
2941
if (self -> insert_pis && this != Py_None ) {
2907
2942
if (treebuilder_add_subelement (this , pi ) < 0 )
2908
2943
goto error ;
2944
+ Py_INCREF (pi );
2945
+ Py_XSETREF (self -> last_for_tail , pi );
2909
2946
}
2910
2947
} else {
2911
2948
pi = PyTuple_Pack (2 , target , text );
@@ -3599,7 +3636,7 @@ expat_pi_handler(XMLParserObject* self, const XML_Char* target_in,
3599
3636
/* shortcut */
3600
3637
TreeBuilderObject * target = (TreeBuilderObject * ) self -> target ;
3601
3638
3602
- if (target -> events_append && target -> pi_event_obj ) {
3639
+ if (target -> events_append && target -> pi_event_obj || target -> insert_pis ) {
3603
3640
pi_target = PyUnicode_DecodeUTF8 (target_in , strlen (target_in ), "strict" );
3604
3641
if (!pi_target )
3605
3642
goto error ;
0 commit comments