2016-03-01 98 views
2

这可能是一个棘手的问题,尽管我对XPath并不熟悉。几天来我的脑子一直在ra ra。 我试图提取从一个XML文件的某些元件以创建一个表,从中我然后需要通过对extractValue提取单个值:XPath查询从XML中提取信息

SELECT [extractValue statements] FROM TABLE(XMLSequence(extract(lv_xml, lv_xpath))) t; 

在该表(一列)的每行应包含一个片段XML所在元素的出现次数不超过一次。它的父节点也应该被提取到表中。问题是,在XML源代码中,所需的元素可能有同样符合我的要求的兄弟。我需要兄弟姐妹在结果表中以单独的行结束。

的XML类似于这样(只是多了很多内容,并以不同的ID):

<element id="Address"> 
    <assignment name="name1" category="cat1" /> 
    <field id="field1"> 
    </field> 
    <field id="field2"> 
    </field> 
    <field id="field3"> 
    <assignment name="name5" category="cat2" /> 
    <assignment name="name12" category="cat2" /> 
    </field> 
</element> 
<element id="PersonInfo"> 
    <field id="field1"> 
    </field> 
    <field id="field2"> 
    <assignment name="name17" category="cat1" /> 
    </field> 
    <field id="field3"> 
    </field> 
    <field id="field4"> 
    </field> 
</element> 
etc etc 

我想要的“任务”的元素,再加上他们的祖先。但正如我上面所说的,我的restults表不能在每行中包含多个“赋值”元素。到目前为止,我试过的东西似乎是提取了很多,如果其中两个是兄弟姐妹。 除此之外,'赋值'可以是'元素'的孩子或'场'的孩子,这可能会增加复杂性。

要实现100%清楚,我的结果需要看起来像这样(为了使后续extractValue一起工作):

<element id="Address"> 
    <assignment name="name1" category="cat1" /> 
</element> 

<element id="Address"> 
    <field id="field3"> 
    <assignment name="name5" category="cat2" /> 
    </field> 
</element> 

<element id="Address"> 
    <field id="field3"> 
    <assignment name="name12" category="cat2" /> 
    </field> 
</element> 

<element id="PersonInfo"> 
    <field id="field2"> 
    <assignment name="name17" category="cat1" /> 
    </field> 
</element> 

我已经与XPath查询玩耍,但没有运气远。我期待

//assignment/ancestor-or-self::* 

可能会做的伎俩,但我显然是错的。有没有办法达到我想要的?

+0

因此,每个条目都有最顶层的父元素:'element'? – Neijwiert

+0

感谢您的评论 - 是的。 始终存在。有时存在,但并非总是如此。 – Amalia

+0

您可以使用XSLT吗? – Neijwiert

回答

1

给定的输入:

<?xml version="1.0" encoding="UTF-8"?> 

<root> 
    <element id="Address"> 
    <assignment name="name1" category="cat1"/> 
    <field id="field1"></field> 
    <field id="field2"></field> 
    <field id="field3"> 
     <assignment name="name5" category="cat2"/> 
     <assignment name="name12" category="cat2"/> 
    </field> 
    </element> 
    <element id="PersonInfo"> 
    <field id="field1"></field> 
    <field id="field2"> 
     <assignment name="name17" category="cat1"/> 
    </field> 
    <field id="field3"></field> 
    <field id="field4"></field> 
    </element> 
</root> 

按照给定的XSL样式表:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:strip-space elements="*"/> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select="//assignment"/> 
</xsl:template> 

<xsl:template match="assignment"> 
    <xsl:apply-templates select="ancestor::element"> 
    <xsl:with-param name="assignment-name" select="@name"/> 
    <xsl:with-param name="field-id" select="ancestor::field/@id"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="element"> 
    <xsl:param name="assignment-name"/> 
    <xsl:param name="field-id"/> 

    <xsl:copy> 
    <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
     <xsl:with-param name="field-id" select="$field-id"/> 
    </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="@*|node()" mode="copy"> 
    <xsl:param name="assignment-name"/> 
    <xsl:param name="field-id"/> 

    <xsl:copy> 
    <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
     <xsl:with-param name="field-id" select="$field-id"/> 
    </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="field" mode="copy"> 
    <xsl:param name="assignment-name"/> 
    <xsl:param name="field-id"/> 

    <xsl:if test="@id=$field-id"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
     <xsl:with-param name="field-id" select="$field-id"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="assignment" mode="copy"> 
    <xsl:param name="assignment-name"/> 
    <xsl:param name="field-id"/> 

    <xsl:if test="@name=$assignment-name"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
     <xsl:with-param name="field-id" select="$field-id"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 

将产生输出:

<?xml version="1.0" encoding="UTF-8"?> 

<element id="Address"> 
    <assignment name="name1" category="cat1"/> 
</element> 
<element id="Address"> 
    <field id="field3"> 
     <assignment name="name5" category="cat2"/> 
    </field> 
</element> 
<element id="Address"> 
    <field id="field3"> 
     <assignment name="name12" category="cat2"/> 
    </field> 
</element> 
<element id="PersonInfo"> 
    <field id="field2"> 
     <assignment name="name17" category="cat1"/> 
    </field> 
</element> 

说明:

首先,我们必须要匹配的所有assignment元素。这些分配元素可以具有fieldelement作为直接父级。它们分别具有idname作为唯一标识符,分别为elementfield。然后,我们只需递归复制,并在id和/或名称匹配的情况下执行额外的检查。我使用modes来确保我没有无限递归。

编辑

ID检查似乎没有必要,你可以检查它是否有名称的子任务。此解决方案效果更好,因为它允许嵌套field元素。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:strip-space elements="*"/> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select="//assignment"/> 
</xsl:template> 

<xsl:template match="assignment"> 
    <xsl:apply-templates select="ancestor::element"> 
    <xsl:with-param name="assignment-name" select="@name"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="element"> 
    <xsl:param name="assignment-name"/> 

    <xsl:copy> 
    <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
    </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="@*|node()" mode="copy"> 
    <xsl:param name="assignment-name"/> 

    <xsl:copy> 
    <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
    </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="field" mode="copy"> 
    <xsl:param name="assignment-name"/> 

    <xsl:if test="child::assignment[@name=$assignment-name]"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="assignment" mode="copy"> 
    <xsl:param name="assignment-name"/> 

    <xsl:if test="@name=$assignment-name"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" mode="copy"> 
     <xsl:with-param name="assignment-name" select="$assignment-name"/> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:if> 
</xsl:template> 

</xsl:stylesheet> 
+0

这真是太棒了。非常感谢。我一直在玩它,并调整它,以适应我的实际情况,它出色地工作 - 除了一个案例。 “分配”元素的属性“名称”的值不必是唯一的。 “元素”或“字段”元素可以具有多个“分配”元素作为具有完全相同名称的子元素(“类别”也可以是相同的,但这不太可能)。在这些情况下,XSL转换的输出将在每个部分包含多个“分配”标签,这意味着我无法处理它。 有没有办法解决这个问题? – Amalia