XSLT将两个节点合并为一个

时间:2016-02-08 06:55:59

标签: xslt

我希望将两个节点(或更多)合并为一个节点。我已经和xslt合作了一段时间,但主要做的很简单。我做了很多搜索,但解决方案已经超出我的想法,所以我无法适应自己的问题。我发现的最近的事情是Martin Honnen使用他建立的一个名为“消除深度相等重复”的函数的答案。

我的问题是我可以拥有两个或更多具有“CoverageCd = ADDRL”的<Coverage>个节点,我只需要组合这些节点,没有其他Coverage节点与其他CoverageCd值。所以我想合并ADDRL节点,但为所有ADDRL迭代保留唯一的“Addr”子节点。

另一个警告是我需要计算合并的ADDRL节点并放在“OptionValue”元素中。所以在我的示例中,我有两个ADDRL Coverage节点,我的OptionValue需要为2.我的xslt目前几乎给了我所需要的东西,但重复了我不想要的MiscParty / GeneralPartyInfo。虽然我有变量AddrlCount,它给我正确的值放在我的OptionValue中,

我不太确定如何将其纳入当前的xslt。我知道我的主要问题是我不完全确定“消除深度相等重复”功能正在做什么。任何人都可以提供的帮助将不胜感激。

输入XML

<ACORD>
    <InsuranceSvcRq>
        <HomePolicyQuoteInqRq>
            <HomeLineBusiness>
                <Dwell LocationRef="000b3c6b-264f-83b7-1b80-006a3ce1f40e">
      <PolicyTypeCd>06</PolicyTypeCd>
      <PurchaseDt>2011-05-10</PurchaseDt>
      <Construction>
        <ConstructionCd>F</ConstructionCd>
        <com.ormutual_recontype>Standard</com.ormutual_recontype>
        <YearBuilt>1988</YearBuilt>
        <BldgArea>
          <NumUnits>1200</NumUnits>
          <UnitMeasurementCd>Square Foot</UnitMeasurementCd>
        </BldgArea>
      </Construction>
                    <Coverage>
                        <CoverageCd>MEDPM</CoverageCd>
                        <Limit>
                            <FormatInteger>1000</FormatInteger>
                        </Limit>
                    </Coverage>
                    <Coverage>
                        <CoverageCd>LAC</CoverageCd>
                        <Limit>
                            <FormatInteger>50000</FormatInteger>
                        </Limit>
                    </Coverage>
                    <Coverage>
                        <CoverageCd>ADDRL</CoverageCd>
                        <Option>
                            <OptionTypeCd>Num1</OptionTypeCd>
                            <OptionValue>1</OptionValue>
                        </Option>
                        <MiscParty>
                            <GeneralPartyInfo>
                                <Addr>
                                    <AddrTypeCd>StreetAddress</AddrTypeCd>
                                    <Addr1>9325 SW CAMILLE TER</Addr1>
                                    <City>PORTLAND</City>
                                    <StateProvCd>OR</StateProvCd>
                                    <PostalCode>97223</PostalCode>
                                    <County>WASHINGTON</County>
                                </Addr>
                            </GeneralPartyInfo>
                        </MiscParty>
                    </Coverage>
                    <Coverage>
                        <CoverageCd>ADDRL</CoverageCd>
                        <Option>
                            <OptionTypeCd>Num1</OptionTypeCd>
                            <OptionValue>1</OptionValue>
                        </Option>
                        <MiscParty>
                            <GeneralPartyInfo>
                                <Addr>
                                    <AddrTypeCd>StreetAddress</AddrTypeCd>
                                    <Addr1>2222 ANDREW AVE NW</Addr1>
                                    <City>SALEM</City>
                                    <StateProvCd>OR</StateProvCd>
                                    <PostalCode>97304</PostalCode>
                                    <County>POLK</County>
                                </Addr>
                            </GeneralPartyInfo>
                        </MiscParty>
                    </Coverage>
                </Dwell>
            </HomeLineBusiness>
        </HomePolicyQuoteInqRq>
    </InsuranceSvcRq>
</ACORD>

期望输出

<ACORD>
    <InsuranceSvcRq>
        <HomePolicyQuoteInqRq>
            <HomeLineBusiness>
                <Dwell LocationRef="000b3c6b-264f-83b7-1b80-006a3ce1f40e">
      <PolicyTypeCd>06</PolicyTypeCd>
      <PurchaseDt>2011-05-10</PurchaseDt>
      <Construction>
        <ConstructionCd>F</ConstructionCd>
        <com.ormutual_recontype>Standard</com.ormutual_recontype>
        <YearBuilt>1988</YearBuilt>
        <BldgArea>
          <NumUnits>1200</NumUnits>
          <UnitMeasurementCd>Square Foot</UnitMeasurementCd>
        </BldgArea>
      </Construction>
                    <Coverage>
                        <CoverageCd>MEDPM</CoverageCd>
                        <Limit>
                            <FormatInteger>1000</FormatInteger>
                        </Limit>
                    </Coverage>
                    <Coverage>
                        <CoverageCd>LAC</CoverageCd>
                        <Limit>
                            <FormatInteger>50000</FormatInteger>
                        </Limit>
                    </Coverage>
                    <Coverage>
                        <CoverageCd>ADDRL</CoverageCd>
                        <Option>
                            <OptionTypeCd>Num1</OptionTypeCd>
                            <OptionValue>2</OptionValue>
                        </Option>
                        <MiscParty>
                            <GeneralPartyInfo>
                                <Addr>
                                    <AddrTypeCd>StreetAddress</AddrTypeCd>
                                    <Addr1>9325 SW CAMILLE TER</Addr1>
                                    <City>PORTLAND</City>
                                    <StateProvCd>OR</StateProvCd>
                                    <PostalCode>97223</PostalCode>
                                    <County>WASHINGTON</County>
                                </Addr>
                                <Addr>
                                    <AddrTypeCd>StreetAddress</AddrTypeCd>
                                    <Addr1>2222 ANDREW AVE NW</Addr1>
                                    <City>SALEM</City>
                                    <StateProvCd>OR</StateProvCd>
                                    <PostalCode>97304</PostalCode>
                                    <County>POLK</County>
                                </Addr>
                            </GeneralPartyInfo>
                        </MiscParty>
                    </Coverage>
                </Dwell>
            </HomeLineBusiness>
        </HomePolicyQuoteInqRq>
    </InsuranceSvcRq>
</ACORD>

我对xslt的尝试

<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:functx="http://www.functx.com" xmlns:mf="http://example.com/mf" exclude-result-prefixes="xs functx mf">
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>

    <xsl:function name="functx:index-of-node" as="xs:integer*">
        <xsl:param name="nodes" as="node()*"/>
        <xsl:param name="nodeToFind" as="node()"/>

        <xsl:sequence select="   for $seq in (1 to count($nodes))   return $seq[$nodes[$seq] is $nodeToFind]  "/>
    </xsl:function>

    <xsl:function name="mf:eliminate-deep-equal-duplicates" as="node()*">
        <xsl:param name="nodes"/>
        <xsl:sequence select="for $node in $nodes             return $node[not(some $preceding-node in $nodes[position() lt functx:index-of-node($nodes, $node)] satisfies deep-equal($node, $preceding-node))]"/>
    </xsl:function>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:variable name="AddrlCount" select="count(ACORD/InsuranceSvcRq/HomePolicyQuoteInqRq/HomeLineBusiness/Dwell/Coverage[./CoverageCd='ADDRL'])"/>
    <xsl:template match="ACORD/InsuranceSvcRq/HomePolicyQuoteInqRq/HomeLineBusiness/Dwell">
        <xsl:copy>
            <xsl:for-each-group select="Coverage" group-by="CoverageCd">
                <xsl:copy>
                    <xsl:apply-templates select="Coverage[./CoverageCd='ADDRL'],
                     mf:eliminate-deep-equal-duplicates(current-group()/(* except (Addr))),
                     Addr"/>
                </xsl:copy>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:0)

您要按Coverage

CoverageCd元素进行分组
<xsl:for-each-group select="Coverage" group-by="CoverageCd">

因此,此时您将定位在Coverage元素上(第一次出现CoverageCd值的元素)。但是你这样做......

<xsl:apply-templates select="Coverage[./CoverageCd='ADDRL'],

这意味着您正在寻找一个Coverage元素,它是覆盖Coverage元素的子元素,它将返回元素。同样,你这样做....

mf:eliminate-deep-equal-duplicates(current-group()/(* except (Addr)))

current-group()返回具有相同代码的所有Coverage元素,其中没有一个元素具有Addr元素,因此这将选择所有元素。

您可以做的只是用以下内容替换声明:

<xsl:apply-templates select="mf:eliminate-deep-equal-duplicates(current-group()/*)" />

然后,您可以拥有匹配要更改的元素的模板。

试试这个XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:functx="http://www.functx.com" xmlns:mf="http://example.com/mf" exclude-result-prefixes="xs functx mf">
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>

    <xsl:function name="functx:index-of-node" as="xs:integer*">
        <xsl:param name="nodes" as="node()*"/>
        <xsl:param name="nodeToFind" as="node()"/>

        <xsl:sequence select="   for $seq in (1 to count($nodes))   return $seq[$nodes[$seq] is $nodeToFind]  "/>
    </xsl:function>

    <xsl:function name="mf:eliminate-deep-equal-duplicates" as="node()*">
        <xsl:param name="nodes"/>
        <xsl:sequence select="for $node in $nodes             return $node[not(some $preceding-node in $nodes[position() lt functx:index-of-node($nodes, $node)] satisfies deep-equal($node, $preceding-node))]"/>
    </xsl:function>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ACORD/InsuranceSvcRq/HomePolicyQuoteInqRq/HomeLineBusiness/Dwell">
        <xsl:copy>
            <xsl:apply-templates select="@*|node() except Coverage" />
            <xsl:for-each-group select="Coverage" group-by="CoverageCd">
                <xsl:copy>
                    <xsl:apply-templates select="mf:eliminate-deep-equal-duplicates(current-group()/*)" />
                </xsl:copy>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="OptionValue">
        <xsl:copy>
            <xsl:value-of select="count(mf:eliminate-deep-equal-duplicates(current-group()/MiscParty/GeneralPartyInfo/Addr))" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="GeneralPartyInfo">
        <xsl:copy>
            <xsl:apply-templates select="mf:eliminate-deep-equal-duplicates(current-group()/MiscParty/GeneralPartyInfo/Addr)" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

说实话,在这种特殊情况下,我甚至不认为你需要mf:eliminate-deep-equal-duplicates。这个XSLT也产生了你需要的结果

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:functx="http://www.functx.com" xmlns:mf="http://example.com/mf" exclude-result-prefixes="xs functx mf">
    <xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ACORD/InsuranceSvcRq/HomePolicyQuoteInqRq/HomeLineBusiness/Dwell">
        <xsl:copy>
            <xsl:apply-templates select="@*|node() except Coverage" />
            <xsl:for-each-group select="Coverage" group-by="CoverageCd">
                <xsl:copy>
                    <xsl:apply-templates  />
                </xsl:copy>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="OptionValue">
        <xsl:copy>
            <xsl:value-of select="count(current-group()/MiscParty/GeneralPartyInfo/Addr)" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="GeneralPartyInfo">
        <xsl:copy>
            <xsl:apply-templates select="current-group()/MiscParty/GeneralPartyInfo/Addr" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>