XSLT 循环遍历具有针对模式的属性的元素

Posted

技术标签:

【中文标题】XSLT 循环遍历具有针对模式的属性的元素【英文标题】:XSLT loop through element with attritbute against a schema 【发布时间】:2020-01-20 00:29:47 【问题描述】:

您好,我对 xml 转换还很陌生。我有一个 delima,我试图循环遍历具有属性和子元素的元素。我正在使用现有文件,即引用模式。我已经尝试了几种不同的循环方式,基于我可以从其他 cmets 收集到的内容,但仍然要么丢弃部分元素,要么根本不显示 输入样本

    <PropertyDetail>
      <parkingType>Surface Lot</parkingType>
      <parkingSpaces>25</parkingSpaces>
      <parkingAssignmentAvailable>true</parkingAssignmentAvailable>
      <parkingAssignedFee>false</parkingAssignedFee>
      <parkingSpaceFee></parkingSpaceFee>
      <parkingComment>parking Comments</parkingComment>

      <parkingType>Garage Lot</parkingType>
      <parkingSpaces>12</parkingSpaces>
      <parkingAssignmentAvailable>true</parkingAssignmentAvailable>
      <parkingAssignedFee>true</parkingAssignedFee>
      <parkingSpaceFee>123.00</parkingSpaceFee>
      <parkingComment>parking Comments</parkingComment>

      <parkingType>Covered Lot</parkingType>
      <parkingSpaces>10</parkingSpaces>
      <parkingAssignmentAvailable>true</parkingAssignmentAvailable>
      <parkingAssignedFee>true</parkingAssignedFee>
      <parkingSpaceFee>75.00</parkingSpaceFee>
      <parkingComment>parking Comments</parkingComment>
   </propertyDetail>

预期输出

  <Information>
    <Parking ParkingType="Surface Lot">
        <Assigned>false</Assigned>
        <AssignedFee></AssignedFee>
        <SpaceFee></SpaceFee>
        <Spaces>25</Spaces>
         <Comment>parking Comments </Comment>
     </Parking>
     <Parking ParkingType="Garage Lot">
         <Assigned>true</Assigned>
         <AssignedFee>Paid</AssignedFee>
         <SpaceFee>123.00</SpaceFee>
         <Spaces>12</Spaces>
         <Comment>parking Comments </Comment>
      </Parking>
      <Parking ParkingType="Covered Lot">
          <Assigned>true</Assigned>
          <AssignedFee>Paid</AssignedFee>
          <SpaceFee>75.00</SpaceFee>
          <Spaces>10</Spaces>
          <Comment>parking Comments </Comment>
       </Parking>
   </Information>

样式表片段

<xsl:for-each select="propertyDetail/parkingType[position()&lt;5]">
            <Parking>

                                <xsl:attribute name="ParkingType">
                                    <xsl:variable name="parkingType" select="current()"/>
                                    <xsl:variable name="MITSParking">
                                        <xsl:value-of
                                            select="$parkingMap/types/type[databaseName=$parkingType]/mits30"
                                        />
                                    </xsl:variable>
                                    <xsl:choose>
                                        <xsl:when test="string-length($MITSParking) > 0">
                                            <xsl:value-of select="$MITSParking"/>
                                        </xsl:when>
                                        <xsl:otherwise>Other</xsl:otherwise>
                                    </xsl:choose>
                                </xsl:attribute>

                            <Assigned>
                                <xsl:choose>
                                    <xsl:when
                                        test="propertyDetail/parkingAssignmentAvailable = 'true'"
                                        >true</xsl:when>
                                    <xsl:when
                                        test="propertyDetail/parkingAssignmentAvailable = 'false'"
                                        >false</xsl:when>
                                    <xsl:otherwise>false</xsl:otherwise>
                                </xsl:choose>
                            </Assigned>
                            <AssignedFee>
                                <xsl:choose>
                                    <xsl:when test="propertyDetail/parkingAssignedFee = 'true'"
                                        >Paid</xsl:when>
                                    <xsl:when test="propertyDetail/parkingAssignedFee = 'false'"
                                        >Free</xsl:when>
                                </xsl:choose>
                            </AssignedFee>
                            <xsl:if test="string(number(propertyDetail/parkingSpaceFee)) != 'NaN' ">
                                <SpaceFee>
                                    <xsl:value-of select="propertyDetail/parkingSpaceFee"/>
                                </SpaceFee>
                            </xsl:if>
                            <xsl:if test="string(number(propertyDetail/parkingSpaces)) != 'NaN'">
                                <Spaces>
                                    <xsl:value-of select="propertyDetail/parkingSpaces"/>
                                </Spaces>
                            </xsl:if>
                            <xsl:if test="string-length(propertyDetail/parkingComment) > 0">
                                <Comment>
                                    <xsl:value-of select="propertyDetail/parkingComment"/>
                                </Comment>
                            </xsl:if>
                        </Parking>
        </xsl:for-each>

架构

<xs:element name="Parking" minOccurs="0" maxOccurs="unbounded">
                          <xs:annotation>
                            <xs:documentation>Type</xs:documentation>
                          </xs:annotation>
                          <xs:complexType>
                            <xs:sequence>
                              <xs:element name="Assigned" type="xs:boolean" minOccurs="0"/>
                              <xs:element name="AssignedFee" minOccurs="0">
                                <xs:simpleType>
                                  <xs:restriction base="xs:string">
                                    <xs:enumeration value="Free"/>
                                    <xs:enumeration value="Paid"/>
                                    <xs:enumeration value="Both"/>
                                  </xs:restriction>
                                </xs:simpleType>
                              </xs:element>
                              <xs:element name="SpaceFee" type="xs:decimal" minOccurs="0"/>
                              <xs:element name="Spaces" type="xs:integer" minOccurs="0"/>
                              <xs:element name="Comment" minOccurs="0">
                                <xs:simpleType>
                                  <xs:restriction base="xs:string">
                                    <xs:maxLength value="500"/>
                                  </xs:restriction>
                                </xs:simpleType>
                              </xs:element>
                            </xs:sequence>
                            <xs:attribute name="ParkingType" use="required">
                              <xs:simpleType>
                                <xs:restriction base="xs:string">
                                  <xs:enumeration value="Surface Lot"/>
                                  <xs:enumeration value="Garage Lot"/>
                                  <xs:enumeration value="Covered Lot"/>
                                  <xs:enumeration value="Street"/>
                                  <xs:enumeration value="Other"/>
                                  <xs:enumeration value="None"/>
                                </xs:restriction>
                              </xs:simpleType>
                            </xs:attribute>
                          </xs:complexType>
                        </xs:element>

任何帮助将不胜感激

添加额外代码以进行澄清

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <!--Stylesheet: MITS41.xsl-->
    <xsl:output method="xml" indent="yes"/>

    <xsl:include href="another xsl file"/>

    <xsl:template match="/">
        <PhysicalProperty xmlns:MITS="http://my-company.com/namespace"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:noNamespaceSchemaLocation="file:../supplied schema location">


            <xsl:for-each-group
                    select="/propertyList/property[CODE BLOCK
                <Management>
                    <xsl:attribute name="IDType" >ManagementID</xsl:attribute>
                    <xsl:attribute name="IDRank" >primary</xsl:attribute>
                    <xsl:attribute name="IDValue"><xsl:value-of select="LSManagementCompanyId" /></xsl:attribute>
                    <PropertyContacts>
                        <Companies>
                            <Identification>
                                <xsl:attribute name="IDType">ManagementID</xsl:attribute>
                                <xsl:attribute name="IDRank">primary</xsl:attribute>
                                <xsl:attribute name="IDValue"><xsl:value-of select="LSManagementCompanyId" /></xsl:attribute>
                            </Identification>
                            <CompanyName>
                                <xsl:value-of select="substring(normalize-space(),1,50)"/>
                            </CompanyName>
                            <WebSite>
                                <xsl:value-of select="managementCompanyURL"/>
                            </WebSite>
                            <Logo>
                                <xsl:value-of select="managementCompanyLogo"/>
                            </Logo>
                        </Companies>
                    </PropertyContacts>
                </Management>
            </xsl:for-each-group>
            <xsl:for-each
                    select="/propertyList/property[CODE BLOCK]">
                <Property>
                    <xsl:attribute name="IDType"></xsl:attribute>
                    <xsl:attribute name="IDRank"></xsl:attribute>
                    <xsl:attribute name="IDValue"></xsl:attribute>
                    <PropertyID>
                        <Identification>                            
                            <xsl:attribute name="IDType"></xsl:attribute>
                            <xsl:attribute name="IDRank"></xsl:attribute>
                            <xsl:attribute name="IDValue"><xsl:value-of select=""/></xsl:attribute>
                        </Identification>
                        <Identification>
                            <xsl:attribute name="IDType"></xsl:attribute>
                            <xsl:attribute name="IDRank"></xsl:attribute>
                            <xsl:choose>
                                <xsl:when test="">
                                    <xsl:attribute name="IDValue"> <xsl:value-of select=""/></xsl:attribute>
                                </xsl:when>
                                <xsl:otherwise> <xsl:attribute name="IDValue">-1</xsl:attribute></xsl:otherwise>
                            </xsl:choose>
                        </Identification>
                        <Identification>
                            <xsl:attribute name="IDType" ></xsl:attribute>
                            <xsl:attribute name="IDRank" ></xsl:attribute>
                            <xsl:choose>
                                <xsl:when test="">
                                    <xsl:attribute name="IDValue"> <xsl:value-of select="" /></xsl:attribute>
                                </xsl:when>
                                <xsl:otherwise> <xsl:attribute name="IDValue">-1</xsl:attribute></xsl:otherwise>
                            </xsl:choose>                            
                        </Identification>
                        <MarketingName>
                            <xsl:value-of select=""/>
                        </MarketingName>
                        <StructureDescription>
                            <xsl:variable name="shortDescription">
                                <xsl:call-template name="remove-html">
                                    <xsl:with-param name="text">
                                        <xsl:value-of select="propertyDetail/shortDescription"/>
                                    </xsl:with-param>
                                </xsl:call-template>
                            </xsl:variable>
                            <xsl:call-template name="formatStringTruncate">
                                <xsl:with-param name="str"><xsl:value-of select="$shortDescription"/></xsl:with-param>
                                <xsl:with-param name="size"><xsl:value-of select="100"/></xsl:with-param>
                                <xsl:with-param name="delimiter"><xsl:value-of select="' '"/></xsl:with-param>
                            </xsl:call-template>
                        </StructureDescription>
                        <xsl:if test="string-length(WebSiteUrl) &lt;= 100">
                            <WebSite>
                                <xsl:value-of select="WebSiteUrl"/>
                            </WebSite>
                        </xsl:if>
                            <Address AddressType="">                            
                            [CODE BLOCK]
                        </Address>
                        <Phone PhoneType="office">
                            <PhoneNumber>
                                <xsl:variable name="phone">
                                    <xsl:choose>
                                        <xsl:when test="$Variable = 'true' and Property = 'true' and normalize-space(propertyContactPhoneList/phoneNumber[@Variable=$VariableId) = ''">
                                            <xsl:value-of
                                                    select="primaryPhone"
                                            />
                                        </xsl:when>
                                        <xsl:otherwise>
                                            <xsl:value-of
                                                    select="propertyPhoneList/phoneNumber[@Variable=$VariableId]"
                                            />
                                        </xsl:otherwise>
                                    </xsl:choose>
                                </xsl:variable>
                                <xsl:choose>
                                    <xsl:when test="string-length($phone) > 10">
                                        <xsl:value-of select="substring($phone, 1, 3)"/>
                                        <xsl:text>-</xsl:text>
                                        <xsl:value-of select="substring($phone, 4, 3)"/>
                                        <xsl:text>-</xsl:text>
                                        <xsl:value-of select="substring($phone, 7, 4)"/>
                                        <xsl:text>x</xsl:text>
                                        <xsl:value-of select="substring($phone, 11)"/>
                                    </xsl:when>
                                    <xsl:when test="string-length($phone) > 0">
                                        <xsl:value-of select="substring($phone, 1, 3)"/>
                                        <xsl:text>-</xsl:text>
                                        <xsl:value-of select="substring($phone, 4, 3)"/>
                                        <xsl:text>-</xsl:text>
                                        <xsl:value-of select="substring($phone, 7, 4)"/>
                                    </xsl:when>
                                </xsl:choose>
                            </PhoneNumber>
                        </Phone>
                        <Email>
                                <xsl:choose>
                                    <xsl:when test=" $VariableId = 'true' and Property = 'true' and normalize-space(propertyContactEmailList/mailLeadData[@Variable=$VariableId]/email) = ''">
                                        <xsl:value-of
                                                select="primaryContactEmail"
                                        />
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <xsl:value-of
                                                select="propertyContactEmailList/mailLeadData[@Variable=$VariableId]/email"
                                        />
                                    </xsl:otherwise>
                                </xsl:choose>
                            </Email>
                    </PropertyID>
                    <xsl:variable name="VariableId">
                        <xsl:value-of select="propertyDetail/Type"/>
                    </xsl:variable>
                    <ILS_Identification RentalType="Market Rate">
                        <xsl:attribute name="ILS_IdentificationType">
                            <xsl:variable name="IlsIdentificationType">
                                <xsl:value-of
                                        select="$structureMap/=$VariableId]/mits41/ILS_IdentificationType"
                                />
                            </xsl:variable>
                            <xsl:choose>
                                <xsl:when test="string-length($VariableType) > 0">
                                    <xsl:value-of select="$VariableType"/>
                                </xsl:when>
                                <xsl:otherwise>Unspecified</xsl:otherwise>
                            </xsl:choose>
                        </xsl:attribute>
                        <Latitude>
                            <xsl:value-of select="propertyAddress"/>
                        </Latitude>
                        <Longitude>
                            <xsl:value-of select="propertyAddress"/>
                        </Longitude>
                    </ILS_Identification>

                    <Information>

                        <Type>
                            <xsl:variable name="Type">
                                <xsl:value-of
                                        select="$Map//mits41/Type"
                                />
                            </xsl:variable>
                            <xsl:choose>
                                <xsl:when test="string-length($Type) > 0">
                                    <xsl:value-of select="$Type"/>
                                </xsl:when>
                                <xsl:otherwise>Unspecified</xsl:otherwise>
                            </xsl:choose>

                        </Type>
                        <UnitCount>
                            <xsl:value-of select="propertyDetail/unitCount"/>
                        </UnitCount>
                        <xsl:if test="string-length(propertyDetail/yearBuilt) > 0">
                            <YearBuilt>
                                <xsl:value-of select="propertyDetail/yearBuilt"/>
                            </YearBuilt>
                        </xsl:if>
                        <xsl:if test="string-length(propertyDetail/yearRemodeled) > 0">
                            <YearRemodeled>
                                <xsl:value-of select="propertyDetail/yearRemodeled"/>
                            </YearRemodeled>
                        </xsl:if>
                        <xsl:for-each select="officeHours/day">
                            <xsl:sort select="@day" order="ascending" data-type="number"/>
                            <xsl:if test="string-length(sT)> 0 or string-length(eT) > 0">
                                <xsl:call-template name="formatOfficeHours">
                                    <xsl:with-param name="sT" select="sT1"/>
                                    <xsl:with-param name="eT" select="eT1"/>
                                    <xsl:with-param name="dow" select="@dayOfWeek"/>
                                </xsl:call-template>
                            </xsl:if>
                            <xsl:if test="string-length(sT2)> 0 or string-length(eT2) > 0">
                                <xsl:call-template name="formatOfficeHours">
                                    <xsl:with-param name="sT" select="sT2"/>
                                    <xsl:with-param name="eT" select="eT2"/>
                                    <xsl:with-param name="dow" select="@dayOfWeek"/>
                                </xsl:call-template>
                            </xsl:if>
                        </xsl:for-each>
                        <ShortDescription>
                            <xsl:variable name="shortDescription">
                                <xsl:call-template name="remove-html">
                                    <xsl:with-param name="text">
                                        <xsl:value-of select="propertyDetail/shortDescription"/>
                                    </xsl:with-param>
                               </xsl:call-template>
                            </xsl:variable>
                            <xsl:call-template name="formatStringTruncate">
                                <xsl:with-param name="str"><xsl:value-of select="$shortDescription"/></xsl:with-param>
                                <xsl:with-param name="size"><xsl:value-of select="500"/></xsl:with-param>
                                <xsl:with-param name="delimiter"><xsl:value-of select="' '"/></xsl:with-param>
                            </xsl:call-template>
                        </ShortDescription>
                        <LongDescription>
                            <xsl:variable name="fullDescription">
                                <xsl:call-template name="remove-html">
                                    <xsl:with-param name="text">
                                        <xsl:value-of select="propertyDetail/fullDescription"/>
                                    </xsl:with-param>
                                </xsl:call-template>
                            </xsl:variable>
                            <xsl:call-template name="formatStringTruncate">
                                <xsl:with-param name="str"><xsl:value-of select="$fullDescription"/></xsl:with-param>
                                <xsl:with-param name="size"><xsl:value-of select="1000"/></xsl:with-param>
                                <xsl:with-param name="delimiter"><xsl:value-of select="' '"/></xsl:with-param>
                            </xsl:call-template>
                        </LongDescription>
                        <xsl:variable name="numberLeaseTerms">
                            <xsl:value-of select="count(propertyDetail/length/leaseTerm)"/>
                        </xsl:variable>
                        <xsl:variable name="validLeaseTerms">
                            <xsl:value-of select="count(propertyDetail/lleangth/lTerm[()])"/>
                        </xsl:variable>
                        <length>
                            <xsl:choose>
                                <xsl:when test="$validLeaseTerms>0">
                                    <xsl:for-each select="propertyDetail/length/leaseTerm[(.=$Map/mits20/length)]">
                                        <xsl:value-of select="."/>
                                        <xsl:if test="position() != last()">
                                            <xsl:text>,</xsl:text>
                                        </xsl:if>
                                    </xsl:for-each>
                                </xsl:when>
                                <xsl:when test="$numberLeaseTerms=1 and propertyDetail/length/leaseTerm='None'">None</xsl:when>
                                <xsl:otherwise>Variable</xsl:otherwise>
                            </xsl:choose>
                        </length>
                        <Parking>
                            <xsl:for-each select="propertyDetail/parkingType">
                                <xsl:attribute name="ParkingType">
                                    <xsl:variable name="parkingType" select="current()"/>
                                    <xsl:variable name="MITSParking">
                                        <xsl:value-of
                                                select="$parkingMap/types/type[databaseName=$parkingType]/mits41"
                                        />
                                    </xsl:variable>
                                    <xsl:choose>
                                        <xsl:when test="string-length($MITSParking) > 0">
                                            <xsl:value-of select="$MITSParking"/>
                                        </xsl:when>
                                        <xsl:otherwise>Other</xsl:otherwise>
                                    </xsl:choose>
                                </xsl:attribute>
                            </xsl:for-each>
                            <Assigned>
                                <xsl:choose>
                                    <xsl:when
                                            test="propertyDetail/parkingAssignmentAvailable = 'true'"
                                    >true</xsl:when>
                                    <xsl:when
                                            test="propertyDetail/parkingAssignmentAvailable = 'false'"
                                    >false</xsl:when>
                                    <xsl:otherwise>false</xsl:otherwise>
                                </xsl:choose>
                            </Assigned>
                            <AssignedFee>
                                <xsl:choose>
                                    <xsl:when test="propertyDetail/parkingAssignedFee = 'true'"
                                    >Paid</xsl:when>
                                    <xsl:when test="propertyDetail/parkingAssignedFee = 'false'"
                                    >Free</xsl:when>
                                </xsl:choose>
                            </AssignedFee>
                            <xsl:if test="string(number(propertyDetail/parkingSpaceFee)) != 'NaN' ">
                                <SpaceFee>
                                    <xsl:value-of select="propertyDetail/parkingSpaceFee"/>
                                </SpaceFee>
                            </xsl:if>
                            <xsl:if test="string(number(propertyDetail/parkingSpaces)) != 'NaN'">
                                <Spaces>
                                    <xsl:value-of select="propertyDetail/parkingSpaces"/>
                                </Spaces>
                            </xsl:if>
                            <xsl:if test="string-length(propertyDetail/parkingComment) > 0">
                                <Comment>
                                    <xsl:value-of select="propertyDetail/parkingComment"/>
                                </Comment>
                            </xsl:if>
                        </Parking>

                    </Information>

                </Property>
            </xsl:for-each>
        </PhysicalProperty>
    </xsl:template>
</xsl:stylesheet>

【问题讨论】:

架构似乎是所需的输出 - 不确定它与手头的问题有多相关。另请注意,您的输入不是格式正确的 XML:&lt;PropertyDetail&gt;&lt;/propertyDetail&gt; 不匹配。 【参考方案1】:

AFAICT,你想做的事:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/propertyDetail">
    <Information>
        <xsl:for-each-group select="*" group-starting-with="parkingType">
            <Parking ParkingType=".">
                <xsl:apply-templates select="current-group() except ."/>
            </Parking>
        </xsl:for-each-group>
    </Information>
</xsl:template>

<xsl:template match="parkingAssignmentAvailable">
    <Assigned>
        <xsl:value-of select="."/>
    </Assigned>
</xsl:template>

<xsl:template match="parkingAssignedFee">
    <AssignedFee>
        <xsl:choose>
            <xsl:when test=".='true'">Paid</xsl:when>
            <xsl:when test=".='false'">Free</xsl:when>
        </xsl:choose>               
    </AssignedFee>
</xsl:template>

<xsl:template match="parkingSpaceFee">
    <SpaceFee>
        <xsl:value-of select="."/>
    </SpaceFee>
</xsl:template>

<xsl:template match="parkingSpaces">
    <Spaces>
        <xsl:value-of select="."/>
    </Spaces>
</xsl:template>

<xsl:template match="parkingComment">
    <Comment>
        <xsl:value-of select="."/>
    </Comment>
</xsl:template>

</xsl:stylesheet>

演示(已修正输入):https://xsltfiddle.liberty-development.net/pPJ8LUX/2

【讨论】:

感谢您的回复。不幸的是,我提供的 sn-p 只是较大样式表的一部分,它已经有一个***模板。当我使用您提供的内容更新该部分时,我收到以下错误“元素 xsl:template 必须是***的(xsl:stylesheet、xsl:transform 或 xsl:package 的子级)” 可以改用命名模板吗? 所有模板都必须是***的。如果没有看到整个图片,恐怕我无法为您提供帮助 - 请参阅:minimal reproducible example。 @Frank,如果您使用xsl:template match="propertyDetail" 而不是xsl:template match="/propertyDetail",Michael 的代码对于任何级别的propertyDetail 元素都可以正常工作。放弃“循环”的想法,并使用带有不同模板的推送样式处理,其余代码使用apply-templates,Michael 的建议将适合任何更大的上下文。 将此代码与现有代码集成的最佳方式可能是采用管道的形式:第一步是将平面结构分组以反映内在层次结构,下一步是处理该层次结构结构。

以上是关于XSLT 循环遍历具有针对模式的属性的元素的主要内容,如果未能解决你的问题,请参考以下文章

使用 xslt 2.0 合并具有相同父属性值的元素的 xml 内容

循环遍历具有可观察属性的 Knockout 可观察对象数组

XSLT 如何从不同的标签级别访问属性?

xslt将具有相同属性的相邻兄弟合并为一个,同时连接它们的文本

XSLT 希望删除属性然后重新匹配元素

使用 XSLT 进行属性转换