【问题标题】:Adding an XML Processing Instruction just before the element if there are only one or zero (empty) elements如果只有一个或零个(空)元素,则在元素之前添加 XML 处理指令
【发布时间】:2016-03-31 23:16:33
【问题描述】:

我有以下 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处理指令(PI)可以在xslt中添加如下。

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

我怎样才能改变上面的模板来完成这件事。任何帮助表示赞赏。

【问题讨论】:

  • 这是对处理指令的糟糕使用。如果这对你很重要,那肯定不是“标准”。
  • 我改变了我的 xslt 模板如下。 然后它在所有非空元素之前给我 PI .但是我怎样才能为空元素做到这一点。

标签: xml xslt xslt-1.0 xslt-2.0


【解决方案1】:

对于您现有的模板,替换父元素,您可以直接添加指令

<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>

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

您也可以将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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2020-02-17
    • 2021-01-01
    • 2017-05-26
    • 2021-01-23
    • 2016-05-06
    相关资源
    最近更新 更多