Используя xslt, преобразуйте один XML-документ на основе содержимого второго XML-документа.

StackOverflow https://stackoverflow.com/questions/647324

  •  22-07-2019
  •  | 
  •  

Вопрос

У меня есть один набор документов, которые неявно определяют разрешенные поля для второго набора объектов, которые должны быть преобразованы в третий набор документов ( какие "правила" используемый документ зависит от содержимого преобразуемого файла), например

<!-- One example rules document --> 
<document object="obj1_rules">
<field name="A"/>
<field name="B"/>
<field name="C"/>
</document>

<!-- Document to be tranformed based upon obj1_rules--> 
<document object="obj1">
<field name="A"/>
<field name="B"/>
<field name="C"/>
<field name="D"/>
<field name="E"/>
</document>

<!-- Desired result--> 
<document object="obj1">
<newfield name="A"/>
<newfield name="B"/>
<newfield name="C"/>
</document>

Возможно ли сделать это преобразование с помощью xslt?

Я вижу, что " в XSLT нет способа создания выражений XPath (например, ссылки на переменные) во время выполнения. " Итак, мне не повезло, или я просто смотрю на эту проблему неправильно? Спасибо!

Это было полезно?

Решение

Вот простое решение :

Это преобразование .

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
<!--                                                   -->  
    <xsl:variable name="vrtfRules">
        <document object="obj1_rules">
            <field name="A"/>
            <field name="B"/>
            <field name="C"/>
        </document>
    </xsl:variable>
<!--                                                   -->  
    <xsl:variable name="vRules" select=
     "document('')/*/xsl:variable
                   [@name = 'vrtfRules']
                     /*
     "/>
<!--                                                   -->  
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
<!--                                                   -->  
    <xsl:template match="field">
      <xsl:if test="@name = $vRules/*/@name">
        <newfield>
          <xsl:apply-templates select="node()|@*"/>
        </newfield>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

при применении к оригинальному исходному XML-документу:

<document object="obj1">
    <field name="A"/>
    <field name="B"/>
    <field name="C"/>
    <field name="D"/>
    <field name="E"/>
</document>

дает желаемый результат:

<document object="obj1">
   <newfield name="A"/>
   <newfield name="B"/>
   <newfield name="C"/>
</document>

Обратите внимание , что " документ о правилах " находится в таблице стилей только для компактности. Когда это отдельный документ, просто document () должна быть скорректирована с учетом фактического href .

Другие советы

Возможно, я упрощаю, но есть ли причина, по которой ваш " документ о правилах " не может быть просто XSLT?

Хорошо, я понимаю, почему вы хотите иметь правила в простом xml-файле, а не в полноценной таблице стилей xsl, но вы просто пропускаете шаг.

Вам нужно создать таблицу стилей xsl, которая преобразует документ правила xml в таблицу стилей xsl, которую вы затем примените к исходному XML.

Хитрость заключается в том, что пространства имен не должны путаться из-за сочетания примененных правил xsl и сгенерированных правил xsl.

    <?xml version="1.0" ?>
    <xsl:stylesheet
        xmlns="YOUR_NAMESPACE_HERE"
        xmlns:output="http://www.w3.org/1999/XSL/Transform"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">

        <xsl:output
            method="xml"
            indent="yes"
            media-type="text/xsl" />

        <xsl:template match="/">
            <output:stylesheet version="2.0">
                <xsl:apply-templates />
            </output:stylesheet>
        </xsl:template>

        <xsl:template match="document[@object]">
            <output:template match="document[@object='{@object}']">
                <output:copy>
                    <xsl:apply-templates />
                </output:copy>
            </output:template>
        </xsl:template>

        <xsl:template match="field[@name]">
            <output:if test="field[@name='{@name}']">
                <output:copy-of select="field[@name='{@name}']" />
            </output:if>
        </xsl:template>

    </xsl:stylesheet>

Я предполагал, что вы будете использовать один и тот же атрибут объекта документа в правилах и в самих документах (это намного проще, imo).

Итак, вы управляете своим документом правил через таблицу стилей выше. В результате получается новая таблица стилей xsl, которая в точности соответствует тому, что вы описываете в своем документе правила xml. Затем вы применяете эту результирующую таблицу стилей к исходному документу, и вы должны получить ожидаемый результат.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top