如果只有一个或零个(空)元素,则在元素之前添加 XML 处理指令

Adding an XML Processing Instruction just before the element if there are only one or zero (empty) elements

我有以下 xml,

  <Standards xmlns="http://ws.wso2.org/dataservice">
    <Standard>
        <ProductID>200057</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1001</SNumber>
        <Year>1986</Year>
        <Designation>ISO 1001:1986</Designation>
        <Publisher>ISO</Publisher>
        <ProductDescriptions>
            <ProductDescription>
                <LanguageCode>en</LanguageCode>
                <DescriptionID>372980</DescriptionID>
            </ProductDescription>
            <ProductDescription>
                <LanguageCode>fr</LanguageCode>
                <DescriptionID>1878599</DescriptionID>
            </ProductDescription>
        </ProductDescriptions>
        <IndustryCodes/>
        <ProductAttributes/>
        <ProductReconfirmationNotices/>
    </Standard>
</Standards>

并想将其转换成下面的格式。

<Standards xmlns="http://ws.wso2.org/dataservice">
    <Standard>
        <ProductID>200057</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1001</SNumber>
        <Year>1986</Year>
        <Designation>ISO 1001:1986</Designation>
        <Publisher>ISO</Publisher>
        <ProductDescriptions>
            <LanguageCode>en</LanguageCode>
            <DescriptionID>372980</DescriptionID>
        </ProductDescriptions>
        <ProductDescriptions>
            <LanguageCode>fr</LanguageCode>
            <DescriptionID>1878599</DescriptionID>
        </ProductDescriptions>
        <IndustryCodes/>
        <ProductAttributes/>
    </Standard>
</Standards>

我能够使用以下 xslt 模板匹配项来完成此操作。所做的是将所有具有 ProductDescription 或 IndustryCode 或 ProductAttribute 或 SaleItem 或 SaleItemAttribute 等的元素作为子元素,并将其替换为源 xml.

中的父元素名称
  <xsl:template
        match="*[x:ProductDescription]|*[x:IndustryCode]|*[x:ProductAttribute]|*[x:SaleItem]|*[x:SaleItemAttribute]|*[x:SaleItemfile]|*[x:SaleItemPrice]">
        <xsl:apply-templates />
    </xsl:template>
    <!-- Replace "item" with its parent in source XML -->
    <xsl:template
        match="x:ProductDescription|x:IndustryCode|x:ProductAttribute|x:SaleItem|x:SaleItemAttribute|x:SaleItemfile|x:SaleItemPrice">
        <xsl:element name="{name(..)}">
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>

但现在我需要添加一个 XML 处理指令,结果 xml 应该是这样的。如果这里有很多这样的元素,例如 ProductDescription,我只需要在这些元素第一次出现之前添加 PI。如果没有元素(即空元素),例如 IndustryCodes,甚至只有一个元素,例如 Standard,我也需要添加相同的 PI。

<Standards xmlns="http://ws.wso2.org/dataservice">
    <?xml-multiple ?>
    <Standard>
        <ProductID>200057</ProductID>
        <Prefix>ISO</Prefix>
        <SNumber>1001</SNumber>
        <Year>1986</Year>
        <Designation>ISO 1001:1986</Designation>
        <Publisher>ISO</Publisher>
        <?xml-multiple ?>
        <ProductDescriptions>
            <LanguageCode>en</LanguageCode>
            <DescriptionID>372980</DescriptionID>
        </ProductDescriptions>
        <ProductDescriptions>
            <LanguageCode>fr</LanguageCode>
            <DescriptionID>1878599</DescriptionID>
        </ProductDescriptions>
        <?xml-multiple ?>
        <IndustryCodes/>
        <?xml-multiple ?>
        <ProductAttributes/>
    </Standard>
</Standards>

XML可以在xslt中添加如下处理指令(PI)

<xsl:processing-instruction name="xml-multiple"/>

我怎样才能改变上面的模板来完成这件事。感谢任何帮助。

对于你现有的模板,替换了parent元素,你可以直接在指令中添加

<xsl:template
    match="*[x:ProductDescription]|*[x:IndustryCode]|*[x:ProductAttribute]|*[x:SaleItem]|*[x:SaleItemAttribute]|*[x:SaleItemfile]|*[x:SaleItemPrice]">
    <xsl:processing-instruction name="xml-multiple"/>
    <xsl:apply-templates />
</xsl:template>

然后您将需要一个单独的模板来处理空元素

<xsl:template
    match="x:ProductDescriptions|x:IndustryCodes|x:ProductAttributes|x:SaleItems|x:SaleItemAttributes|x:SaleItemfiles|x:SaleItemPrices">
    <xsl:processing-instruction name="xml-multiple"/>
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
    </xsl:copy>
</xsl:template>

请注意,您无需检查它们是否具有 child 个元素。因为当他们有 children 时另一个模板匹配他们,因为它具有更高的优先级(因为它有条件检查)将被使用。

您也可以将 Standard 元素添加到此列表中。

试试这个 XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:x="http://ws.wso2.org/dataservice">
    <xsl:output method="xml" indent="yes" />

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

    <xsl:template
        match="x:Standard|x:ProductDescriptions|x:IndustryCodes|x:ProductAttributes|x:SaleItems|x:SaleItemAttributes|x:SaleItemfiles|x:SaleItemPrices">
        <xsl:processing-instruction name="xml-multiple"/>
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template
        match="*[x:ProductDescription]|*[x:IndustryCode]|*[x:ProductAttribute]|*[x:SaleItem]|*[x:SaleItemAttribute]|*[x:SaleItemfile]|*[x:SaleItemPrice]" >
        <xsl:processing-instruction name="xml-multiple"/>
        <xsl:apply-templates />
    </xsl:template>

    <!-- Replace "item" with its parent in source XML -->
    <xsl:template
         match="x:ProductDescription|x:IndustryCode|x:ProductAttribute|x:SaleItem|x:SaleItemAttribute|x:SaleItemfile|x:SaleItemPrice">
        <xsl:element name="{name(..)}" namespace="http://ws.wso2.org/dataservice">
            <xsl:apply-templates />
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>