我有大量(2k +)的xml文件,我需要从中提取数据并将数据转储到某种类的表中(Excel或只是一个或多个XML文件就可以了)。 有趣的是,xml文件具有截然不同的节点数量(偶尔在子节点中具有相同的名称),并且层次结构的深度也是未知的。
无论如何,这是一个例子:
<?xml version="1.0" encoding="UTF-8"?>
<SomeName>
<identifier>
<UID> 1234 </UID>
</identifier>
<MainNode1>
<SubNode1>
<Subnode1a>DATA1a0</Subnode1a>
</SubNode1>
<SubNode1>
<Subnode1a>DATA1a1</Subnode1a>
</SubNode1>
<SubNode1>
<Subnode1a>DATA1a2</Subnode1a>
</SubNode1>
</MainNode1>
<MainNode2>
<SubNode2>
<Subnode2a>DATA2a0</Subnode2a>
</SubNode2>
<SubNode3>
<Subnode3a>DATA3a0</Subnode3a>
</SubNode3>
<SubNode4>
<Subnode4a>DATA4a0</Subnode4a>
</SubNode4>
</MainNode2>
<MainNodeIDONTCARE>
<SubnodeWhatever>
</SubnodeWhatever>
<MainNodeIDONTCARE>
</SomeName>
这是我的桌子,我希望它能够展平。基本上它应该是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<SomeName>
<UID>1234</UID>
<MainNode1_SubNode1_SubNode1aA>DATA1a0</MainNode1_SubNode1_SubNode1aA>
<MainNode1_SubNode1_SubNode1aB>DATA1a1</MainNode1_SubNode1_SubNode1aB>
<MainNode1_SubNode1_SubNode1aC>DATA1a2</MainNode1_SubNode1_SubNode1aC>
<MainNode2_SubNode2_SubNode2a>Data2a0</MainNode2_SubNode2_SubNode2a>
<MainNode2_SubNode3_SubNode3a>Data3a0</MainNode2_SubNode3_SubNode3a>
<MainNode2_SubNode4_SubNode4a>Data4a0</MainNode2_SubNode4_SubNode4a>
</SomeName>
正如您所看到的,<MainNodeIDONTCARE>
不在表中,因为我只想从XML文件中提取特定的数据集(我想要包含我需要的MainNodes,而忽略所有其他的)。在这种情况下,MainNode1到MainNode4中的任何内容。
完成这项工作的最佳方法是什么?我不关心性能,因为文件不是太大,转换可能需要的时间长。
是否有一些聪明的XSLT或其他任何可以帮助我的东西? 谢谢。
答案 0 :(得分:0)
无论是否使用XSLT(并且是可行的),似乎诀窍是创建一个xpath语句,该语句构成所有这些节点的单个集合。正确的xpath语句不关心深度。
答案 1 :(得分:0)
你在这里:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="SomeName">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="UID" priority="1">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="MainNodeIDONTCARE" priority="1"/>
<xsl:template match="SomeName//*[not(*)][text()]">
<xsl:variable name="elementName">
<xsl:call-template name="getElementName">
<xsl:with-param name="element" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:element name="{$elementName}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template name="getElementName">
<xsl:param name="element"/>
<xsl:if test="$element/parent::*[not(self::SomeName)]">
<xsl:call-template name="getElementName">
<xsl:with-param name="element" select="$element/parent::*"/>
</xsl:call-template>
<xsl:text>_</xsl:text>
</xsl:if>
<xsl:value-of select="name($element)"/>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:0)
使用XSLT 2.0 [Saxon](我认为这不适用于xslt 1.0):
首先,非空文本节点包含数据,因此请选择它们:
<xsl:template match="/SomeName" >
<SomeName>
<xsl:copy-of select="identifier/UID" />
<xsl:apply-templates select="(MainNode1|MainNode2)//text()[normalizespace()]" />
</SomeName>
</xsl:template>
然后你需要通过加入祖先名称来创建一个元素名称:
<xsl:template match="text()" >
<xsl:element name="{string-join( ./ancestor::*[name()!='SomeName']/name(),'_')}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>