【问题标题】:Add child elements in particular order按特定顺序添加子元素
【发布时间】:2017-02-08 01:27:06
【问题描述】:

我正在通过 XSLT 进行 xml 到 xml 的转换。我有以下几点:

stylesheet.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.test.org"
xmlns:xs="http://www.w3.org/2001/XMLSchema"  version="2.0"> <!-- xs namespace allows typed functions and parameters -->
<xsl:output method="xml" indent="yes" version="1.0" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" /> 

<xsl:param name="other-id" select="Request/Order/OtherId" />

<xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:copy-of select="@*" copy-namespaces="no" />
        <xsl:apply-templates select="@*|node()" />
    </xsl:element>
</xsl:template>

<xsl:template match="@*|text()|comment()|processing-instruction()">
    <xsl:copy />
</xsl:template>

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

<xsl:template match="Details">
    <xsl:element name="{local-name()}">
        <xsl:element name="Signon>
            <xsl:element name="SignonDt>2017-01-01</xsl:element>
            <xsl:element name="MessageQuantity">3</xsl:element>
        <xsl:element>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template match="NotificationRq">
    <xsl:element name="{local-name()}">
        <xsl:element name="RqUID">Test</xsl:element>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template match="Policy/SDDCd" />

<xsl:template match="Policy">
    <xsl:element name="{local-name()}">
        <xsl:element name="RFDCd">
            <xsl:call-template name="getRFDCd" />
        </xsl:element>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<xsl:template name="getRFDCd">
    <xsl:choose>
        <xsl:when test="contains($other-id, 'RFD 2')">
            <xsl:text>AUB</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <xsl:text>CL</xsl:text>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

<xsl:template match="Contact/Addr" >
    <xsl:element name="{local-name()}">
        <xsl:element name="AddrTypeCd">StreetAddress</xsl:element>
        <xsl:apply-templates />
    </xsl:element>
</xsl:template>

<!-- other templates structured similar to these -->

input.xml

<Request>
    <Details>
        <NotificationRq>
            <RqDate>2017-01-01</RqDate>
            <RqDetails>
            <!-- other children -->
            <RqDetails>
        </NotificationRq>
        <Policy>
            <PolNumber>1234567890</PolNumber>
            <SDDCd>T35</SDDCd>
        </Policy>
        <Contact>
            <Addr>
                <AddrLn1>Test address line 1</AddrLn1>
                <AddrLn2>Test address line 2</AddrLn2>
                <PostCode>AX12D3</PostCode>
            </Addr>
        </Contact>
        <!-- other children -->
    </Details>
</Request>

输出.xml

<Details xmlns="http://test.org">
    <Signon>
        <SignonDt>2017-01-01</Signon>
        <MessageQuantity>3</MessageQuantity>
    </Signon>
    <NotificationRq>
        <RqUId>Test</RqUID>
        <RqDate>2017-01-01</RqDate>
        <RqDetails>
            <!-- other children -->
        <RqDetails>
    </NotificationRq>
    <Policy>
        <RFDCd>CL</RFDCd>
        <PolNumber>1234567890</PolNumber>
    </Policy>
    <Contact>
        <Addr>
            <AddrTypeCd>StreetAddress</AddrTypeCd>
            <AddrLn1>Test address line 1</AddrLn1>
            <AddrLn2>Test address line 2</AddrLn2>
            <PostCode>AX12D3</PostCode>
        </Addr>
    </Contact>
    <!-- other children -->
</Details>

注意:由于较早的问题,我正在使用&lt;xsl:element name="{local-name()}"&gt;;我正在将没有命名空间的源 xml 复制到新的输出中,这个解决方案以及身份转换旁边的额外模板修复了将命名空间属性添加到所有元素的问题

问题是,这个 xml 被发送到下游进行模式验证的地方,因此,新创建的子元素的位置很重要。如上面的 sn-ps 所示,新的子元素被添加为父元素的第一个子元素。在某些情况下,这很好,这是它们应该在的位置,但是对于大约一半的已创建元素,它们必须出现在最后(奇数的一两个需要插入到指定位置)。仍以 input.xml 为例,以下是所需输出的外观:

desired-output.xml

<Details xmlns="http://test.org">
    <NotificationRq>
        <RqDate>2017-01-01</RqDate>
        <RqDetails>
            <!-- other children -->
        <RqDetails>
        <RqUId>Test</RqUID>
    </NotificationRq>
    <Signon>
        <SignonDt>2017-01-01</Signon>
        <MessageQuantity>3</MessageQuantity>
    </Signon>
    <Policy>
        <PolNumber>1234567890</PolNumber>
        <RFDCd>CL</RFDCd>
    </Policy>
    <Contact>
        <Addr>
            <AddrLn1>Test address line 1</AddrLn1>
            <AddrLn2>Test address line 2</AddrLn2>
            <AddrTypeCd>StreetAddress</AddrTypeCd>
            <PostCode>AX12D3</PostCode>
        </Addr>
    </Contact>
    <!-- other children -->
</Details>

有没有办法指定新子元素应该出现在元素的现有子顺序中的哪个位置?我的某个模板是否导致插入顺序始终位于首位?

附加信息:我看过一些关于特定订单插入的问题,但它们通常似乎是针对一系列元素或一系列重复元素,例如如何在一系列作者元素中插入另一个作者元素,解决方案倾向于使用位置函数来确定是否循环到正确的索引,然后插入。我正在使用的 xml 由独特的元素组成,这些元素可能包含一个值或可能包含多个子项(其中一些包含子项等)。 xml 中没有重复元素,所以我认为我不能使用上述解决方案(除非有人知道如何为元素的非重复子项做这样的事情)。另外,我使用的是 Saxon HE 版本 9.7.0-8

【问题讨论】:

    标签: xslt xpath


    【解决方案1】:

    为什么不能简单点:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://www.test.org"> 
    <xsl:output method="xml" indent="yes" version="1.0" encoding="UTF-8" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*" /> 
    
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:copy-of select="@*" />
            <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="comment()|processing-instruction()">
        <xsl:copy/>
    </xsl:template>
    
    <xsl:template match="/*">
        <xsl:apply-templates/>
    </xsl:template>
    
    <xsl:template match="NotificationRq">
        <NotificationRq>
            <xsl:apply-templates/>
            <RqUId>Test</RqUId>
         </NotificationRq>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 如果您的意思是为什么不直接使用元素本身而不是 &lt;xsl:element&gt;,我遇到了一个问题,即除非通过 xsl:Element 定义自定义元素(可能是转换器引擎问题?),否则不会出现自定义元素。如果您的意思是用&lt;xsl:apply-templates /&gt; 切换元素定义,它仍然会导致&lt;RqUId&gt; 作为&lt;NotificationRq&gt; 中的第一个子元素出现。另外,我注意到您删除了其中一个模板的一些 select 语句,这是故意的,即也尝试这样做吗?
    • 我查看了您的输入和所需的输出,并提出了我认为从一个到另一个的最简单的方法。结果是不是和你要求的不一样?
    • 不,我尝试将&lt;xsl:apply-templates /&gt; 的位置与元素标记交换,结果与“不想要的”输出相同; RqUId 仍然是 NotificationRq 的第一个孩子,而不是最后一个
    • 奇怪,我会进一步调查,以防有什么明显的我遗漏了。假设是这种情况并且可行,我仍然有在元素子元素中的指定位置插入新元素的问题。我将更新所需的输出 xmls 和样式表来演示
    • "我仍然有在元素子元素中的指定位置插入新元素的问题。" 同样的事情:在新元素;创建新元素;将模板应用于其余元素。
    猜你喜欢
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-25
    • 1970-01-01
    相关资源
    最近更新 更多