如何获取XML叶子节点的完整层级路径及对应值?
XML叶子节点完整路径提取方案
问题背景
给定一段XML结构代码,需要提取所有叶子节点的完整层级路径(从根节点下一级开始,以.分隔),并输出路径与对应节点值的映射,格式为路径 值。
给定XML代码片段
<Profile> <Settings> <PresentationParameters> <Annualize>True</Annualize> <LoadExAnteRiskForPresentation>False</LoadExAnteRiskForPresentation> <MultiLegDisplayMode>Legs</MultiLegDisplayMode> <Parameters> <InitialDisplayMode>CollapseToPositions</InitialDisplayMode> <InitialExpandCollapseLevel>-1</InitialExpandCollapseLevel> </Parameters> <PivotExpandCollapseStrategy>ExpandAllStrategy</PivotExpandCollapseStrategy> <RollupExternallyManagedSleeves>False</RollupExternallyManagedSleeves> <SharedParameters> <AssetBasisInEffect> <CalculationType>Invalid</CalculationType> <IsColumnBasisInvested>False</IsColumnBasisInvested> <Type>Standard</Type> <Value>MWB_SESSION</Value> </AssetBasisInEffect> <AssetBasisSaveable> <CalculationType>Invalid</CalculationType> <IsColumnBasisInvested>False</IsColumnBasisInvested> <Type>Standard</Type> <Value>MWB_SESSION</Value> </AssetBasisSaveable> <CurrencySaveable> <Mode>GROUP</Mode> </CurrencySaveable> <IsSessionBasisInEffect>True</IsSessionBasisInEffect> </SharedParameters> <ShowPositionsGrandTotal>True</ShowPositionsGrandTotal> <TargetingCurrency> <Mode>GROUP</Mode> </TargetingCurrency> <TransposeColumns>False</TransposeColumns> <UnitBasisMeasureOption>PercentagePoints</UnitBasisMeasureOption> <UnitTrustConstituentMode>DoNotDisplay</UnitTrustConstituentMode> <WeightProrationOption>Default</WeightProrationOption> </PresentationParameters> </Settings> </Profile>
期望输出格式
Settings.PresentationParameters.Annualize TRUE Settings.PresentationParameters.LoadExAnteRiskForPresentation FALSE Settings.PresentationParameters.MultiLegDisplayMode Legs Settings.PresentationParameters.Parameters.InitialDisplayMode CollapseToPositions Settings.PresentationParameters.Parameters.InitialExpandCollapseLevel -1 Settings.PresentationParameters.PivotExpandCollapseStrategy ExpandAllStrategy Settings.PresentationParameters.RollupExternallyManagedSleeves FALSE Settings.PresentationParameters.SharedParameters.AssetBasisInEffect.CalculationType Invalid Settings.PresentationParameters.SharedParameters.AssetBasisInEffect.IsColumnBasisInvested FALSE Settings.PresentationParameters.SharedParameters.AssetBasisInEffect.Type Standard Settings.PresentationParameters.SharedParameters.AssetBasisInEffect.Value MWB_SESSION Settings.PresentationParameters.SharedParameters.AssetBasisSaveable.CalculationType Invalid Settings.PresentationParameters.SharedParameters.AssetBasisSaveable.IsColumnBasisInvested FALSE Settings.PresentationParameters.SharedParameters.AssetBasisSaveable.Type Standard Settings.PresentationParameters.SharedParameters.AssetBasisSaveable.Value MWB_SESSION Settings.PresentationParameters.SharedParameters.CurrencySaveable.Mode GROUP Settings.PresentationParameters.SharedParameters.IsSessionBasisInEffect TRUE Settings.PresentationParameters.ShowPositionsGrandTotal TRUE Settings.PresentationParameters.TargetingCurrency.Mode GROUP Settings.PresentationParameters.TransposeColumns FALSE Settings.PresentationParameters.UnitBasisMeasureOption PercentagePoints Settings.PresentationParameters.UnitTrustConstituentMode DoNotDisplay Settings.PresentationParameters.WeightProrationOption Default
实现方案
1. Python 实现(使用标准库xml.etree.ElementTree)
核心思路:递归遍历XML节点,判断当前节点是否为叶子节点(无直接子元素),若是则从父节点开始拼接完整路径,最后输出路径和节点文本值(可按需转换大小写)。
import xml.etree.ElementTree as ET def get_leaf_paths(element, current_path=""): # 拼接当前节点到路径中 new_path = f"{current_path}.{element.tag}" if current_path else element.tag # 判断是否为叶子节点:无直接子元素 if len(element) == 0: # 去除根节点Profile,只保留Settings开始的路径 if new_path.startswith("Profile."): output_path = new_path[len("Profile."):] else: output_path = new_path # 转换值为大写(按需调整) value = element.text.strip().upper() if element.text else "" print(f"{output_path} {value}") else: # 递归遍历子节点 for child in element: get_leaf_paths(child, new_path) # 解析XML(可替换为fromstring直接解析XML字符串) tree = ET.parse("profile.xml") root = tree.getroot() # 开始遍历 get_leaf_paths(root)
2. Java 实现(使用DOM解析)
核心思路:通过DOM解析XML,递归遍历节点,记录当前层级路径,遇到叶子节点时输出路径和值。
import org.w3c.dom.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; public class XMLLeafPathExtractor { public static void main(String[] args) { try { File xmlFile = new File("profile.xml"); // 替换为你的XML文件路径 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(xmlFile); doc.getDocumentElement().normalize(); traverseNode(doc.getDocumentElement(), ""); } catch (Exception e) { e.printStackTrace(); } } private static void traverseNode(Node node, String currentPath) { if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; String newPath = currentPath.isEmpty() ? element.getTagName() : currentPath + "." + element.getTagName(); NodeList childNodes = element.getChildNodes(); boolean isLeaf = true; // 判断是否为叶子节点:子节点中没有其他元素节点 for (int i = 0; i < childNodes.getLength(); i++) { Node child = childNodes.item(i); if (child.getNodeType() == Node.ELEMENT_NODE) { isLeaf = false; traverseNode(child, newPath); } } if (isLeaf) { // 去除根节点Profile if (newPath.startsWith("Profile.")) { String outputPath = newPath.substring("Profile.".length()); String value = element.getTextContent().trim().toUpperCase(); System.out.println(outputPath + " " + value); } } } } }
3. PowerShell 实现
核心思路:使用Select-Xml结合XPath表达式//*[not(*)]筛选所有叶子节点,再通过节点的ParentNode属性回溯拼接完整路径。
# 读取XML文件 $xml = [xml](Get-Content "profile.xml") # 替换为你的XML文件路径 # 筛选所有叶子节点(无子元素的元素) $leafNodes = Select-Xml -Xml $xml -XPath "//*[not(*)]" foreach ($node in $leafNodes) { $pathParts = @() $currentNode = $node.Node # 回溯父节点,拼接路径 while ($currentNode -ne $xml.Profile) { $pathParts += $currentNode.Name $currentNode = $currentNode.ParentNode } # 反转路径顺序,拼接为正常层级 $path = ($pathParts | Reverse) -join "." $value = $node.Node.InnerText.Trim().ToUpper() Write-Output "$path $value" }
内容的提问来源于stack exchange,提问作者NoazDad
相关产品推荐
相关产品推荐

