我需要在文档中的一个级别对大多数子节点进行重新排序。
该文档的结构看起来(简化)如下:
sheet
table
row
parameters
row
parameters
row
parameters
row
cell
header string
cell
header string
cell
header string
data row A
cell
data
cell
data
cell
data
data row B
cell
data
cell
data
cell
data
data row C
cell
data
cell
data
cell
data
data row D
cell
data
cell
data
cell
data
data row E
cell
data
cell
data
cell
data
row
parameters
row
parameters
row
parameters
row
parameters
row
parameters
我现在正在使用 pugixml 来加载、解析、遍历和访问大型 xml 文件,并且我最终正在处理一个新的数据行序列。我知道我正在正确解析所有内容,并且查看重新排序结果,我可以看到读取和处理是正确的。经过我所有的优化和处理后的重新排序解决方案是一个按修改顺序排列的指标列表,例如上面示例的 { D,A,E,C,B }。所以现在我需要将它们重新排序为这个新顺序,然后将生成的 xml 输出到一个新文件中。实际数据大约16兆,有几百个数据元素行节点,每行有一百多个数据元素
我编写了一个例程来交换两个数据行,但我正在做的事情是在交换期间破坏 xml 结构的一致性。我确定我不理解 pugi 移动节点和/或使节点句柄无效的方式。
我创建并留出节点句柄——pugi::xml_node——到“表”级节点、“标题”行节点和“第一个数据”行节点,在上面的原始形式中是节点“数据行 A”。我知道这些句柄让我可以正确访问正确的数据——我可以在优化和重新排序计算期间暂停执行并查看它们,并检查行及其同级并查看输入顺序。
“标题行”始终是表的特定子项,“第一个数据行”始终是紧随“标题行”之后的兄弟。所以我在加载文件并检查它们的数据一致性时设置了这些。
我对 node::insert_copy_before 的理解是这样的:
pugi:xml_node new_node_handle_in_document = parentnode.insert_copy_before( node_to_be_copied_to_child_of_parent , node_to_be_copied_nodes_next_sibling )
我的理解是,具有所有子节点和属性的 node_to_be_copied_to_child_of_parent 的深度递归克隆将作为兄弟节点插入到 node_to_be_copied_nodes_next_sibling 之前,其中两者都是父节点的子节点。
显然,如果 node_to_be_copied_nodes_next_sibling 也是“第一个数据行”,那么第一个数据行的节点句柄在操作后可能仍然有效,但实际上不再是第一个数据节点的句柄。但是在文档上使用 insert_copy 是否会强制更新附近的单个节点句柄 - 或者不是 - 的更改?
所以让我们看一下我正在尝试制作的代码:
// a method to switch data rows
bool switchDataRows( int iRow1 , int iRow2 )
{
// temp vars
int iloop;
// navigate to the first row and create a handle that can move along siblings until we find the target
pugi::xml_node xmnRow1 = m_xmnFirstDataRow;
for ( iloop = 0 ; iloop < iRow1 ; iloop++ )
xmnRow1 = xmnRow1.next_sibling();
// navigate to the second row and create another handle that can move along siblings until we find the target
pugi::xml_node xmnRow2 = m_xmnFirstDataRow;
for ( iloop = 0 ; iloop < iRow2 ; iloop++ )
xmnRow2 = xmnRow2.next_sibling();
// ok.... so now get convenient handles on the the locations of the two nodes by creating handles to the nodes AFTER each
pugi::xml_node xmnNodeAfterFirstNode = xmnRow1.next_sibling();
pugi::xml_node xmnNodeAfterSecondNode = xmnRow2.next_sibling();
// 此时我知道我创建的所有句柄都指向预期的数据。
// now copy the second to the location before the first
pugi::xml_node xmnNewRow2 = m_xmnTableNode.insert_copy_before( xmnRow2 , xmnNodeAfterFirstNode );
// 这就是我关心的地方。此副本是否按照我的要求执行,将第二个目标行的副本移动到表节点下的位置 // 作为 xmnNodeAfterFirstNode 之前的子节点?如果是这样,此操作是否会使数据行节点的其他句柄无效?// 一旦我们在兄弟列表中进行插入/复制,是否所有的赌注都结束了,或者该子列表中其他节点的句柄是否仍然有效?
// now copy the first to the spot before the second
pugi::xml_node xmnNewRow1 = m_xmnTableNode.insert_copy_before( xmnRow1 , xmnNodeAfterSecondNode );
// 显然,如果数据行节点的其他句柄已被第一个 insert_copy 无效,那么这些句柄就不再有用了...
// now delete the old rows
bool bDidRemoveRow1 = m_xmnTableNode.remove_child( xmnRow1 );
bool bDidRemoveRow2 = m_xmnTableNode.remove_child( xmnRow2 );
// 这是我尝试在将原始数据行节点复制到新位置后删除它们
// we have to update the first data row!!!!!
bool bDidRowUpdate = updateFirstDataRow(); // a routine that starts with the header row node and finds the first sibling, the first data row
// 和以前一样,如果使用 insert_copy 方法导致许多句柄四处移动,那么我将无法基于标题的“已知”句柄来更新“第一个数据行节点” //句柄数据行节点。
// return the result
return( bDidRemoveRow2 && bDidRemoveRow1 && bDidRowUpdate );
}
正如我所说,这破坏了生成的 xml 的结构一致性。我可以保存它,但除了记事本之外什么都不会读取它。桌子最终有点乱码。如果我尝试使用自己的程序阅读它,阅读器会报告“元素不匹配”错误并拒绝加载它,这是可以理解的。
所以我做错了一件或多件事。这些是什么?