1

我正在尝试进行 XSL 转换,它将所有以小写字母“[az]”开头的叶子标签转换为父标签的属性。一切正常,直到叶子标签在标签顺序中真正下降。例如

请参考下面的xml。转换跳过了“sessionId”标签,因为它位于末尾;但是,如果我将它放在“PaginationData”标签之前,转换将正常工作。

问:是否可以更正 XSL,使其不考虑标签排序。

问:有人能解释一下为什么像'sessionId'标签这样的标签顺序存在问题吗?

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="Carz.com">
<SOAP-ENV:Body>
    <ns1:getCarValuedAvail>
        <CarValuedAvailRQ>
            <PaginationData>
                <pageNumber>1</pageNumber>
                <itemsPerPage/>
            </PaginationData>
            <BuyDate>
                <date>20130509</date>
                <time/>
            </BuyDate>
            <SellDate>
                <date>20130511</date>
                <time/>
            </SellDate>
            <Destination>
                <Name/>
                <ZoneList/>
                <type>SIMPLE</type>
                <code>PMI</code>
            </Destination>
            <OccupancyList>
                <CarOccupancy>
                    <SpaceCount>1</SpaceCount>
                    <Occupancy/>
                    <ServiceOccupancy>
                        <AdultCount>1</AdultCount>
                        <ChildCount>0</ChildCount>
                        <GuestList/>
                    </ServiceOccupancy>
                </CarOccupancy>
            </OccupancyList>
            <CarCodeList/>
            <CategoryList/>
            <BoardList/>
            <ShowDirectPayment/>
            <ShowNetPrice/>
            <Credentials>
                <User>xyz</User>
                <Password>xyz</Password>
            </Credentials>
            <sessionId>DummySessionId</sessionId>
        </CarValuedAvailRQ>
    </ns1:getCarValuedAvail>
</SOAP-ENV:Body>

请参考下面的 XSL -

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

 <xsl:template match="//*[not(*)][contains('abcdefghijklmnopqrstuvwxyz',substring(local-name(),0,2))]">
    <xsl:attribute name="{name()}">
        <xsl:value-of select="text()"/>
    </xsl:attribute>
</xsl:template>

<xsl:template match="*">
    <xsl:copy>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

预期输出:如您所见,所有以小(非大写)字符开头的标签都已转换为其父标签的属性。

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="Carz.com">
<SOAP-ENV:Body>
    <ns1:getCarValuedAvail sessionId="DummySessionId">
        <CarValuedAvailRQ>
            <PaginationData pageNumber="1" itemsPerPage=""/>
            <BuyDate date="20130509" time=""/>
            <SellDate date="20130511" time=""/>
            <Destination type="Simple" code="PMI">
                <Name/>
                <ZoneList/>
            </Destination>
            <OccupancyList>
                <CarOccupancy>
                    <SpaceCount>1</SpaceCount>
                    <Occupancy/>
                    <ServiceOccupancy>
                        <AdultCount>1</AdultCount>
                        <ChildCount>0</ChildCount>
                        <GuestList/>
                    </ServiceOccupancy>
                </CarOccupancy>
            </OccupancyList>
            <CarCodeList/>
            <CategoryList/>
            <BoardList/>
            <ShowDirectPayment/>
            <ShowNetPrice/>
            <Credentials>
                <User>xyz</User>
                <Password>xyz</Password>
            </Credentials>
        </CarValuedAvailRQ>
    </ns1:getCarValuedAvail>
</SOAP-ENV:Body>

4

1 回答 1

1

我认为您的方法的一个潜在问题是规范要求必须在创建任何子节点之前创建结果树中的任何属性节点;如果在创建子节点后尝试创建属性节点,则处理器需要发出错误信号或丢弃该属性。

因此,基本上您需要稍微改变方法,以确保您在处理任何要转换为属性的元素之前处理其他子元素。由于您已将问题标记为 XSLT 2.0,因此我发布了 XSLT 2.0 解决方案:

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

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

<xsl:template match="*[*[not(*) and matches(local-name(), '^[a-z]')]]">
  <xsl:copy>
    <xsl:apply-templates select="@* , *[not(*) and matches(local-name(), '^[a-z]')]"/>
    <xsl:apply-templates select="node() except *[not(*) and matches(local-name(), '^[a-z]')]"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*[not(*) and matches(local-name(), '^[a-z]')]">
  <xsl:attribute name="{name()}" select="."/>
</xsl:template>

</xsl:stylesheet>

如果您需要使用 XSLT 1.0 解决它,那么您可以按如下方式进行:

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

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

<xsl:template match="*[*[not(*) and contains('abcdefghijklmnopqrstuvwxyz', substring(local-name(), 1, 1))]]">
  <xsl:copy>
    <xsl:apply-templates select="@* | *[not(*) and contains('abcdefghijklmnopqrstuvwxyz', substring(local-name(), 1, 1))]"/>
    <xsl:apply-templates select="node()[not(self::*[not(*) 
                                        and 
                                        contains('abcdefghijklmnopqrstuvwxyz', substring(local-name(), 1, 1))])]"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*[not(*) and contains('abcdefghijklmnopqrstuvwxyz', substring(local-name(), 1, 1))]">
  <xsl:attribute name="{name()}">
    <xsl:value-of select="."/>
  </xsl:attribute>
</xsl:template>

</xsl:stylesheet>
于 2013-04-29T08:39:09.893 回答