xslt:将元素转换为属性 - 仅将最后一个元素作为属性返回

时间:2018-04-06 18:39:48

标签: xml templates xslt attributes

尝试将元素转换为元素父节点的属性,但代码仅返回列表中的最后一个元素作为属性

XML示例

    <?xml version="1.0" encoding="UTF-8"?>
<NB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/Users/xXXXXXX/Documents/xxxxx%20Profile%20XML/Untitled13.xsd">
    <Profile>
        <PName>165370 - XXX - XXXXXX</PName>
        <OrderID>165370</OrderID>
        <Status>I</Status>
        <OrderInst/>
        <TopicInst>OMIT MERE MENTIONS</TopicInst>
        <KeywordInst>
            <OrderKWs>
                <KW>KEEPHILLS</KW>
                <KWInst>ICW KEEPHILLS POWER PLANT
OR ICW POWER GENERATION AT KEEPHILLS PLANT</KWInst>
                <KW>SUN 7 PLANT</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE 7 GAS PLANT</KW>
                <KWInst>ICW POWER PLANT
OR ICW POWER GENERATION</KWInst>
                <KW>SUNDANCE AND COAL</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND ELECTRIC</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND ELECTRICAL</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND ELECTRICITY</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND GAS</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND GENERATION</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND PLANT</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE AND POWER</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>SUNDANCE UNIT</KW>
                <KWInst>ICW SUNDANCE GAS FIRED POWER PLANT
OR ICW SUNDANCE COAL FIRED POWER PLANT
OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT
OMIT SUNDANCE FILM FESTIVAL</KWInst>
                <KW>WABAMUN</KW>
                <KWInst>ICW WABUMUM POWER PLANT
OR ICW POWER GENERATION AT WABUMUM PLANT</KWInst>
            </OrderKWs>
        </KeywordInst>
    </Profile>
</NB>

XSD

    <?xml version="1.0" encoding="UTF-8"?>
<!-- W3C Schema generated by XMLSpy v2018 sp1 (http://www.altova.com) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="KW" type="xs:string"/>
    <xs:element name="NB">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="Profile"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="PName">
        <xs:simpleType>
            <xs:restriction base="xs:string">
                <xs:enumeration value="165370 - XXX - XXXXXX"/>
            </xs:restriction>
        </xs:simpleType>
    </xs:element>
    <xs:element name="KWInst" type="xs:string"/>
    <xs:element name="Status">
        <xs:simpleType>
            <xs:restriction base="xs:string">
                <xs:enumeration value="I"/>
            </xs:restriction>
        </xs:simpleType>
    </xs:element>
    <xs:element name="OrderID" type="xs:int"/>
    <xs:element name="Profile">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="PName"/>
                <xs:element ref="OrderID"/>
                <xs:element ref="Status"/>
                <xs:element ref="OrderInst"/>
                <xs:element ref="TopicInst"/>
                <xs:element ref="KeywordInst"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="OrderKWs">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
                <xs:element ref="KW"/>
                <xs:element ref="KWInst"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="OrderInst">
        <xs:complexType/>
    </xs:element>
    <xs:element name="TopicInst">
        <xs:simpleType>
            <xs:restriction base="xs:string">
                <xs:enumeration value="OMIT MERE MENTIONS"/>
            </xs:restriction>
        </xs:simpleType>
    </xs:element>
    <xs:element name="KeywordInst">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="OrderKWs"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

XSLT

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:math="http://www.w3.org/2005/xpath-functions/math" xmlns:array="http://www.w3.org/2005/xpath-functions/array" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:err="http://www.w3.org/2005/xqt-errors" exclude-result-prefixes="array fn map math xhtml xs err" version="3.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <xsl:apply-templates mode="copy" select="."/>
    </xsl:template>
    <xsl:template match="*|text()|@*" mode="copy">
        <xsl:copy>
            <xsl:apply-templates mode="copy" select="@*"/>
            <xsl:apply-templates mode="copy"/>
        </xsl:copy>
    </xsl:template>
 <xsl:template match="//KeywordInst" mode="copy">
        <xsl:copy>
            <xsl:apply-templates mode="convert-to-attr" select="OrderKWs/*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*" mode="convert-to-attr">
        <xsl:attribute name="{name()}" select="text()"/>
    </xsl:template>
</xsl:stylesheet>

输出XML

    <?xml version="1.0" encoding="UTF-8"?>
<NB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/Users/gary.larose/Documents/Newbase%20Profile%20XML/Untitled13.xsd">
    <Profile>
        <PName>165370 - XXX - XXXXXX</PName>
        <OrderID>165370</OrderID>
        <Status>I</Status>
        <OrderInst/>
        <TopicInst>OMIT MERE MENTIONS</TopicInst>
        <KeywordInst KW="WABAMUN" KWInst="ICW WABUMUM POWER PLANT&#xA;OR ICW POWER GENERATION AT WABUMUM PLANT"/>
    </Profile>
</NB>

预期产出:

    <?xml version="1.0" encoding="UTF-8"?>
<NB xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file:///C:/Users/gary.larose/Documents/Newbase%20Profile%20XML/Untitled13.xsd">
    <Profile>
        <PName>165370 - XXX - XXXXXX</PName>
        <OrderID>165370</OrderID>
        <Status>I</Status>
        <OrderInst/>
        <TopicInst>OMIT MERE MENTIONS</TopicInst>
        <KeywordInst  KW="KEEPHILLS" KWInst="ICW KEEPHILLS POWER PLANT OR ICW POWER GENERATION AT KEEPHILLS PLANT"</>
        <KeywordInst KW="SUN 7 PLANT" KWInst="ICW SUNDANCE GAS FIRED POWER PLANT OR ICW SUNDANCE COAL FIRED POWER PLANTOR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANTOMIT SUNDANCE FILM FESTIVAL"</>
        <KeywordInst KW="SUNDANCE 7 GAS PLANT" KWInst="ICW POWER PLANT OR ICW POWER GENERATION"</>
        <KeywordInst KW="SUNDANCE AND COAL" KWInst="ICW SUNDANCE GAS FIRED POWER PLANT OR ICW SUNDANCE COAL FIRED POWER PLANT OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT OMIT SUNDANCE FILM FESTIVAL"</>
        <KeywordInst KW="SUNDANCE AND ELECTRIC" KWInst="ICW SUNDANCE GAS FIRED POWER PLANT OR ICW SUNDANCE COAL FIRED POWER PLANTOR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANTOMIT SUNDANCE FILM FESTIVAL"</>
        <KeywordInst KW="SUNDANCE AND ELECTRICAL" KWInst="ICW SUNDANCE GAS FIRED POWER PLANT OR ICW SUNDANCE COAL FIRED POWER PLANT OR ICW ELECTRICAL POWER GENERATION AT SUNDANCE PLANT OMIT SUNDANCE FILM FESTIVAL"</>
        ......
        <KeywordInst KW="WABAMUN" KWInst="ICW WABUMUM POWER PLANT&#xA;OR ICW POWER GENERATION AT WABUMUM PLANT"/>
    </Profile>
</NB>

属性KW =“WABAMUN”和KWInst =“ICW ....”是示例xml文件中的最后一对。我的目标文件具有相同结构的150k行,当我在目标文件上运行此XSLT时,Output(如已采样)似乎始终是Profile实体中列表中的最后一对KW和KWInst。

谢谢你的帮助。 ģ

1 个答案:

答案 0 :(得分:1)

如果您知道(第一个)元素的名称(例如KW)以形成新的KeywordInst元素,那么我认为使用XSLT 2或3最简单的方法是使用例如for-each-group starting-with="KW"所以使用XSLT 3就变成了

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="KeywordInst">
      <xsl:for-each-group select="OrderKWs/*" group-starting-with="KW">
          <xsl:copy select="../..">
              <xsl:apply-templates select="current-group()" mode="element-to-attribute"/>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>

  <xsl:template match="*" mode="element-to-attribute">
      <xsl:attribute name="{name()}" select="."/>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/nc4NzPY

使用XSLT 2,您需要拼出身份转换而不是使用xsl:mode声明,而您没有xsl:copy select,因此您需要使用其他方式,例如:使用

对名称进行硬编码
  <xsl:template match="KeywordInst">
      <xsl:for-each-group select="OrderKWs/*" group-starting-with="KW">
          <KeywordInst>
              <xsl:apply-templates select="current-group()" mode="element-to-attribute"/>
          </KeywordInst>
      </xsl:for-each-group>
  </xsl:template>

但分组保持不变。