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()<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) <= 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:<PropertyDetail>
与 </propertyDetail>
不匹配。
【参考方案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 内容