搜索更优雅的xsl,用于解析具有可变元素的嵌套xml

时间:2014-03-19 09:49:50

标签: xml xslt

我有这个xml,我想转换为另一个xml。

我想要做的是定义一个<xsl:value-of select=""/>,当<waarde>为'0110'时,<nummer>会获得<waarde>的值。 当<rubriek>没有值时,xml中不存在完整的<persoon>元素。 我需要知道元素是否缺失所以我可以在生成的.xml中创建一个空元素。

源xml中可能有多个<rubriek>元素,其中部分或全部包含<nummer><waarde>包含'0110'。 在那种情况下,我想要来自相应<waarde1></waarde1> <waarde2></waarde2元素的所有值,它们应该在目标xml中显示为<?xml version="1.0" encoding="UTF-8"?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:gbavAntwoord xmlns:ns2="http://www.competent.nl/gbav/v1"> <identificatie> <indicatie>xx</indicatie> <interneAfnemer/> <gebruiker>xx</gebruiker> <profielNaam>xx</profielNaam> <internKenmerk/> </identificatie> <resultaten> <persoon> <categorieen> <categorie> <nummer>01</nummer> <naam>Persoon</naam> <rubrieken> <rubriek> <nummer>0110</nummer> <naam>A-nummer</naam> <waarde>1234567</waarde> <omschrijving>1234567</omschrijving> </rubriek> <rubriek> <nummer>0120</nummer> <naam>BSN</naam> <waarde>1234567</waarde> <omschrijving>1234567</omschrijving> </rubriek> </rubrieken> </categorie> <categorie> <nummer>02</nummer> <naam>Ouder1</naam> <rubrieken> <rubriek> <nummer>0110</nummer> <naam>A-nummer</naam> <waarde>4567890</waarde> <omschrijving>4567890</omschrijving> </rubriek> <rubriek> <nummer>0120</nummer> <naam>BSN</naam> <waarde>4567890</waarde> <omschrijving>4567890</omschrijving> </rubriek> </rubrieken> </categorie> <categorie> <nummer>02</nummer> <naam>Ouder1</naam> <rubrieken> <rubriek> <nummer>0210</nummer> <naam>Voornamen</naam> <waarde>Jane</waarde> <omschrijving>Jane</omschrijving> </rubriek> <rubriek> <nummer>0230</nummer> <naam>Voorvoegsels geslachtsnaam</naam> <waarde>van der</waarde> <omschrijving>van de</omschrijving> </rubriek> </rubrieken> </categorie> </categorieen> </persoon> </resultaten> </ns2:gbavAntwoord> </S:Body> </S:Envelope>

<xsl:if test="not </>

我在xsl中有一个可行的解决方案,但它不是很优雅,有很多双打。 <xsl:for-each select="/S:Envelope/S:Body/*[namespace-uri()='http://www.competent.nl/gbav/v1' and local-name()='gbavAntwoord']/resultaten/persoon"> <xsl:for-each select="current()/categorieen"> <xsl:for-each select="current()/categorie"> <xsl:variable name="currentCategorie" select="nummer/text()"/> <xsl:for-each select="current()/rubrieken"> <!-- 230, voorvoegsel geslachtsnaam, kan leeg zijn. Element moet dan wel opgenomen worden --> <xsl:if test="$currentCategorie='01' or $currentCategorie='05'"> <xsl:if test="not (rubriek/nummer/text()='0230')"> <P1010230>not available</P1010230> </xsl:if> </xsl:if> <xsl:for-each select="current()/rubriek"> <!-- per categorie de juiste rubrieknummers uitlezen --> <xsl:if test="$currentCategorie='01'"> <!-- <varValue> <xsl:value-of select="$currentCategorie"></xsl:value-of></varValue> <Pl010120> <xsl:value-of select="waarde/text()"></xsl:value-of> </Pl010120> --> <xsl:if test="nummer/text()='0120'"> <Pl010120> <xsl:value-of select="waarde/text()"/> </Pl010120> </xsl:if> 代码需要多次,我也检查for-each循环中的相同元素。

{{1}}

底线:是否可以使用一个或另一个xsl构造/函数以更好的方式实现这一点然后我想出来了?

1 个答案:

答案 0 :(得分:0)

你的问题是一个非常普遍的问题,你似乎没有问题,可以这么说。 Stackoverflow实际上并不是要求代码审查的地方(例如:“如何更优雅地编程?”)。正确的地方是Code Review StackExchange Site

但是既然我正在写作,是的,你的代码还有很大的改进空间。

for-each

的误用

for-each(和一般的循环)是一个过程构造,经常被XSLT的初学者过度使用,即在错误的地方使用。您可以在单独的模板中重写所有for-each元素,这是组织样式表的更实用的方法。所有元素名称都是事先静态知道的,循环相对简单。

if vs. predicates

正如您所注意到的,代码中有很多xsl:if个元素。这也可以通过使用谓词编写单独的模板来完成。例如,以下条件:

<xsl:if test="nummer/text()='0120'">

可以在单独的模板中编写为:

<xsl:template match="nummer[.='0120']">

<强>缩写

虽然您的代码在语法上是正确的,但有很多方法可以大大缩短它。不需要使用current()为表达式加前缀,如:

<xsl:for-each select="current()/categorieen">

因为此for-each的上下文无论如何都是当前节点。写作:

<xsl:for-each select="categorieen">

会做同样的事情。同样地,text()在很多地方都很重要,例如:

<xsl:if test="nummer/text()='0120'">

因为XSLT处理器在这样的比较中隐式选择元素的文本节点。所以,这个:

<xsl:if test="nummer='0120'">

是一样的。

<强>命名空间

您没有显示整个样式表,但似乎您没有在样式表中声明名称空间http://www.competent.nl/gbav/v1。而是在XPath表达式中测试此命名空间:

namespace-uri()='http://www.competent.nl/gbav/v1'

这确实可以更优雅地完成。通常,所有名称空间都在xsl:stylesheet元素上声明,然后由它们的前缀引用:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ns2="http://www.competent.nl/gbav/v1">

然后,您可以使用ns2:gbavAntwoord引用此命名空间中的元素。