【问题标题】:XML - XSLT - Using two XML files - Additions to XML file consulting another XML fileXML - XSLT - 使用两个 XML 文件 - 对 XML 文件的补充咨询另一个 XML 文件
【发布时间】:2018-07-05 22:53:26
【问题描述】:

我有以下问题,对我来说,有点棘手,

基本上我需要能够使用存储在另一个 XML 文件中的数据来修改一个 XML 输入文件,所以我必须使用 2 个输入 XML 文件,

我有以下 XML 文件,这是我要修改的文件(基本上,只是对其进行添加):

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
    <text-prop name="displayName">PersonTemplate</text-prop>
    <setup>
        <simple-master-page name="MasterPage" id="2">
            <footer>
                <text id="3">
                    <prop name="contentType">html</prop>
                    <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
                </text>
            </footer>
        </simple-master-page>
    </setup>
    <body>
        <table id="4">  
            <column id="17"/>
            <column id="18"/>
            <column id="19"/>
            <header>
                <row id="5">
                    <cell id="6">
                        <label id="20">
                            <text-prop name="text">NameTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="7">
                        <label id="21">
                            <text-prop name="text">CityTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="8">
                        <label id="22">
                            <text-prop name="text">AgeTitle</text-prop>
                        </label>
                    </cell>
                </row>
            </header>
            <detail>
                <row id="9">
                    <cell id="10"/>
                    <cell id="11"/>
                    <cell id="12"/>
                </row>
            </detail>
        </table>
    </body>
</report>

我想通过查阅另一个 XML 文件来对其进行修改/添加,这给了我想要放入第一个 XML 文件的数据:

<?xml version="1.0" encoding="utf-8"?>
<model>
    <layouts>
        <layout ID="001" name="PersonTemplate" format="Table" nFields="3" >
            <fields>
                <field name="NameTitle"/>
                <field name="CityTitle"/>
                <field name="AgeTitle"/>
            </fields>
        </layout>
        <layout ID="002" name="SchoolTemplate" format="Table" nFields="3" >
            <fields>
                <field name="NameTitle"/>
                <field name="LocationTitle"/>
                <field name="MaxCapacityTitle"/>
            </fields>
        </layout>
    </layouts>
    <reports>
        <report layoutID="001">
            <params>
                <sources>
                    <source name="source1" dbURL="sampledb1.com" user="user1" password="dXNlcjE=" driver="dbDriver"/>
                    <source name="source2" dbURL="sampledb2.com" user="user2" password="dXNlcjI=" driver="dbDriver"/>
                </sources>
                <set name="set1" source="source1" querie="select Name, City, Age from PeopleTable" >
                    <qFields>
                        <qField name="Name" type="string"/>
                        <qField name="City" type="string"/>
                        <qField name="Age" type="integer"/>
                    </qFields>
                </set>
            </params>
        </report>
        <report layoutID="002">
            <params>
                <sources>
                    <source name="source1" dbURL="sampledb1.com" user="user1" password="dXNlcjE=" driver="dbDriver"/>
                </sources>
                <set name="Data Set" dataSource="source1" querie="select Name, Location, MaxCapacity from SchoolsTable" >
                    <qFields>
                        <qField name="Name" type="string"/>
                        <qField name="Location" type="string"/>
                        <qField name="MaxCapacity" type="integer"/>
                    </qFields>
                </set>
            </params>
        </report>
    </reports>
</model>

所以,我想生成以下 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
    <text-prop name="displayName">PersonTemplate</text-prop>
     <data-sources>
        <data-source extensionID="this.is.a.fixed.value" name="source1">
            <prop name="DriverClass">dbDriver</prop>
            <prop name="databaseURL">sampledb1.com</prop> 
            <prop name="dbUser">user1</prop>
            <encrypted-prop name="dbPassword" encryptionID="base64">dXNlcjE=</encrypted-prop>
        </data-source>
    </data-sources>
    <data-sets>
        <data-set extensionID="this.is.a.fixed.value" name="set1">
            <list-prop name="columnHints">
                <struct>
                    <prop name="columnName">Name</prop>
                    <text-prop name="displayName">Name</text-prop>
                    <text-prop name="heading">Name</text-prop>
                </struct>
                <struct>
                    <prop name="columnName">City</prop>
                    <text-prop name="displayName">City</text-prop>
                    <text-prop name="heading">City</text-prop>
                </struct>
                <struct>
                    <prop name="columnName">Age</prop>
                    <text-prop name="displayName">Age</text-prop>
                    <text-prop name="heading">Age</text-prop>
                </struct>
            </list-prop>
            <struct name="cachedMetaData">
                <list-prop name="resultSet">
                    <struct>
                        <prop name="position">1</prop>
                        <prop name="name">Name</prop>
                        <prop name="dataType">string</prop>
                    </struct>
                    <struct>
                        <prop name="position">2</prop>
                        <prop name="name">City</prop>
                        <prop name="dataType">string</prop>
                    </struct>
                    <struct>
                        <prop name="position">3</prop>
                        <prop name="name">Age</prop>
                        <prop name="dataType">integer</prop>
                    </struct>
                </list-prop>
            </struct>
            <prop name="dataSource">source1</prop>
            <list-prop name="resultSet">
                <struct>
                    <prop name="position">1</prop>
                    <prop name="name">Name</prop>
                    <prop name="dataType">string</prop>
                </struct>
                <struct>
                    <prop name="position">2</prop>
                    <prop name="name">City</prop>
                    <prop name="dataType">string</prop>
                </struct>
                <struct>
                    <prop name="position">3</prop>
                    <prop name="name">AGE</prop>
                    <prop name="dataType">integer</prop>
                </struct>
            </list-prop>
            <xml-prop name="queryText"><![CDATA[select Name, City, Age from PeopleTable]]></xml-prop>
        </data-set>
    </data-sets>
    <setup>
        <simple-master-page name="MasterPage" id="2">
            <footer>
                <text id="3">
                    <prop name="contentType">html</prop>
                    <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
                </text>
            </footer>
        </simple-master-page>
    </setup>
    <body>
        <table id="4">
            <prop name="dataSet">set1</prop>
            <list-prop name="boundDataColumns">
                <struct>
                    <prop name="name">Name</prop>
                    <text-prop name="displayName">Name</text-prop>
                    <expression name="expression" type="javascript">dataSetRow["Name"]</expression>
                    <prop name="dataType">string</prop>
                </struct>
                <struct>
                    <prop name="name">City</prop>
                    <text-prop name="displayName">City</text-prop>
                    <expression name="expression" type="javascript">dataSetRow["City"]</expression>
                    <prop name="dataType">string</prop>
                </struct>
                <structure>
                    <prop name="name">Age</prop>
                    <text-prop name="displayName">Age</text-prop>
                    <expression name="expression" type="javascript">dataSetRow["Age"]</expression>
                    <prop name="dataType">integer</prop>
                </structure>
            </list-prop>
            <column id="17"/>
            <column id="18"/>
            <column id="19"/>
            <header>
                <row id="5">
                    <cell id="6">
                        <label id="20">
                            <text-prop name="text">NameTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="7">
                        <label id="21">
                            <text-prop name="text">CityTitle</text-prop>
                        </label>
                    </cell>
                    <cell id="8">
                        <label id="22">
                            <text-prop name="text">AgeTitle</text-prop>
                        </label>
                    </cell>
                </row>
            </header>
            <detail>
                <row id="9">
                    <cell id="10">
                         <data>
                            <prop name="resultSetColumn">Name</prop>
                        </data>
                    </cell>
                    <cell id="11">
                         <data>
                            <prop name="resultSetColumn">City</prop>
                        </data>
                    </cell>
                    <cell id="12">
                         <data>
                            <prop name="resultSetColumn">Age</prop>
                        </data>
                    </cell>
                </row>
            </detail>
        </table>
    </body>
</report>

注意: data-source 和 data-set 中的 encryptionIDextensionID 都是固定值。

所以基本上数据来自使用源source1 的集合set1,它也直接来自source1,所以我需要一种从第二个XML 文件中检索正确数据的方法。

如您所见,我可以在第二个 XML 文件中包含许多 layoutreport 元素。所以,首先我想我需要在第一个 XML 文件中找到displayName 属性,然后找到name 属性与displayName 匹配的layout 元素。然后,我需要在第二个 XML 文件中,通过 layout 元素中的 ID 属性,找到在 layoutID 属性中具有相同值的 report 元素。从这里开始,我会找到正确的report 元素。直到现在我才开始更改/添加第一个 XML 文件。这部分我真的不知道该怎么做。我正在尝试做的事情可能吗?

我知道你可以使用 document 函数来处理 2 个 XML 文件,但我真的不知道如何,

我真的需要帮助,谢谢!

编辑

我基本上想复制第一个 XML 文件中的所有内容(已经完成),然后使用存储在第二个 XML 文件(以 &lt;model&gt; 元素开头的那个)中的数据进行添加

更新

因为我希望输出是第一个输入 XML 文件的补充,所以我开始按照@Sojimanatsu 的建议,通过应用身份转换,像这样(在@TimC 的帮助下针对特定问题的帖子特殊字符(XML - XSLT - Escape special characters)):

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design"
                              xpath-default-namespace="http://www.eclipse.org/birt/2005/design">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" />
    <xsl:strip-space elements="*"/>

    <!--copy the whole input XML file-->
    <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>

    <!--special treatment for setup/text-prop element-->
   <xsl:template match="report/setup/simple-master-page/footer/text/text-prop">
     <xsl:copy>
         <xsl:attribute name="name">
             <xsl:text>content</xsl:text>
         </xsl:attribute>
         <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
         <xsl:value-of select="." disable-output-escaping="yes"/>
         <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>

      </xsl:copy>
  </xsl:template> 

</xsl:stylesheet>

注意:处理 setup/text-prop 元素的 XSLT 代码是可选的,因为我的输出 XML 可以有 &amp;lt;value-of&amp;gt;new Date()&amp;lt;/value-of&amp;gt; 而不是 &lt;![CDATA[&lt;value-of&gt;new Date()&lt;/value-of&gt;]]&gt;

所以现在我能够在输出 XML 中准确地打印我在第一个输入 XML 中的内容。现在,正如@Sojimanatsu 所说,我想选择特定标签并使用来自第二个输入 XML 文件的新数据对其进行编辑,并且我还想添加新标签/元素,例如 data-sourcesdata-sets 元素,但是我不知道该怎么做。我知道我必须使用 document() 函数但是如何使用??

首先,如何在&lt;report&gt; 元素下方和&lt;setup&gt; 元素之前添加一个新元素&lt;data-sources&gt;? (&lt;data-sources&gt;&lt;setup&gt; 是兄弟姐妹)

我试过这样做,添加一个新的&lt;xsl:template&gt;

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                              xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design"
                              xpath-default-namespace="http://www.eclipse.org/birt/2005/design">
    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" encoding="utf-8" />
    <xsl:strip-space elements="*"/>

    <!--copy the whole input XML file-->
    <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>

    <!--special treatment for setup/text-prop element-->
   <xsl:template match="report/setup/simple-master-page/footer/text/text-prop">
     <xsl:copy>
         <xsl:attribute name="name">
             <xsl:text>content</xsl:text>
         </xsl:attribute>
         <xsl:text disable-output-escaping="yes">&lt;![CDATA[</xsl:text>
         <xsl:value-of select="." disable-output-escaping="yes"/>
         <xsl:text disable-output-escaping="yes">]]&gt;</xsl:text>

      </xsl:copy>
  </xsl:template>

    <xsl:template match="report/text-prop">
      <xsl:copy-of select="."/>
        <dataSources>DATA SOURCE VALUE</dataSources>
    </xsl:template>

</xsl:stylesheet>

但我得到了这个输出(dataSource 标记出现在正确的位置,但有一些我不知道如何到达那里的属性):

<?xml version="1.0" encoding="utf-8"?>
<report xmlns="http://www.eclipse.org/birt/2005/design" version="3.2.23" id="1">
   <text-prop name="displayName">PersonTemplate</text-prop>
   <dataSources xmlns=""
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:xmlbirtns="http://www.eclipse.org/birt/2005/design">DATA SOURCE VALUE</dataSources>
   <setup>
      <simple-master-page name="MasterPage" id="2">
         <footer>
            <text id="3">
               <prop name="contentType">html</prop>
               <text-prop name="content"><![CDATA[<value-of>new Date()</value-of>]]></text-prop>
            </text>
         </footer>
      </simple-master-page>
   </setup>
   <body>
      <table id="4">
         <column id="17"/>
         <column id="18"/>
         <column id="19"/>
         <header>
            <row id="5">
               <cell id="6">
                  <label id="20">
                     <text-prop name="text">NameTitle</text-prop>
                  </label>
               </cell>
               <cell id="7">
                  <label id="21">
                     <text-prop name="text">CityTitle</text-prop>
                  </label>
               </cell>
               <cell id="8">
                  <label id="22">
                     <text-prop name="text">AgeTitle</text-prop>
                  </label>
               </cell>
            </row>
         </header>
         <detail>
            <row id="9">
               <cell id="10"/>
               <cell id="11"/>
               <cell id="12"/>
            </row>
         </detail>
      </table>
   </body>
</report>

我真正的第一个和第二个输入 XML 文件要大得多,但是一旦我有这个示例工作,我就可以生成我真正的 XML 输出,

谢谢大家!

【问题讨论】:

    标签: xml xslt saxon xslt-3.0


    【解决方案1】:

    我想你基本上是在寻找这个功能。

    document() function

    所以这个函数的想法是能够选择另一个 xml 文件,并基于一些 xpath 迭代,使用该 xml 文件中的一些值,在你的新 xml 中或其他任何东西中。

    【讨论】:

    • 是的,我也这么认为,但我的问题在于生成最终文件的实际 XSLT 代码
    • 而且我也不知道怎么用这个功能
    • 嗯,这是一个学习曲线,对吧?到目前为止您一直在尝试什么 XSLT 可以分享吗?也请清楚地识别问题。您想要的功能是 document() 并且网上有大量示例如何使用它。如果你分享你的 XSLT 代码,我可能会尝试实现。
    • 目前我只是试图将 标记从第一个 XML 文件复制到结果 XML 文件,但我没有做对,我只想将这两个元素完全复制到第一个 XML 文件中,然后将添加的内容应用到该文件中。请参阅 XSLT 小提琴:xsltfiddle.liberty-development.net/6qVRKwg。然后我需要使用 de document() 函数开始查阅第二个 XML 文件。谢谢!!
    • 我不确定我是否理解正确。如果要复制第一个 XML 文件,请检查 XSLT 中的标识模板。这将为您提供整个 XML 文件,然后您可以选择特定标签并使用新内容轻松编辑它们。
    【解决方案2】:

    一般来说,要通过某个值引用元素,您可以使用xsl:key 定义键,然后使用key 函数查找引用的元素。如果是两个单独的文档,如果要在第二个文档中查找值,则需要确保使用key 函数的第三个参数传入目标文档。

    此外,在您的情况下,您正在处理一个包含命名空间中的元素的文档,而第二个包含没有命名空间中的元素的文档,这需要在 XSLT 文档中使用两个命名空间的前缀或使用 xpath-default-namespace 来确保选择正确的命名空间。

    如果您想在某个命名空间中创建新的结果元素,例如您的主要输入文档之一,您需要通过在样式表中声明 xmlns="http://www.eclipse.org/birt/2005/design" 来确保在该命名空间中有结果元素。

    我不清楚您是只想选择某些数据源或数据集,还是只选择一个,以下处理所有引用的源和数据集。此外,仅对于数据源,我尝试添加将以属性为中心的辅助输入数据转换为目标结构的模板,对于您必须自己实现的集合,目前默认模板只是简单地复制它们。

    样式表是(带有二级 XML 内联,当然在你的真实代码中你可以使用&lt;xsl:param name="doc2" select="doc('file2.xml')"/&gt;

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xpath-default-namespace="http://www.eclipse.org/birt/2005/design"
        xmlns="http://www.eclipse.org/birt/2005/design"
        exclude-result-prefixes="xs"
        expand-text="yes"
        version="3.0">
    
      <!-- second document inlined for the example,
           use param name="doc2" select="doc('file2.xml')
           instead to load external file -->
      <xsl:param name="doc2" xmlns="">
    <model>
        <layouts>
            <layout ID="001" name="PersonTemplate" format="Table" nFields="3" >
                <fields>
                    <field name="NameTitle"/>
                    <field name="CityTitle"/>
                    <field name="AgeTitle"/>
                </fields>
            </layout>
            <layout ID="002" name="SchoolTemplate" format="Table" nFields="3" >
                <fields>
                    <field name="NameTitle"/>
                    <field name="LocationTitle"/>
                    <field name="MaxCapacityTitle"/>
                </fields>
            </layout>
        </layouts>
        <reports>
            <report layoutID="001">
                <params>
                    <sources>
                        <source name="source1" dbURL="sampledb1.com" user="user1" password="dXNlcjE=" driver="dbDriver"/>
                        <source name="source2" dbURL="sampledb2.com" user="user2" password="dXNlcjI=" driver="dbDriver"/>
                    </sources>
                    <set name="set1" source="source1" querie="select Name, City, Age from PeopleTable" >
                        <qFields>
                            <qField name="Name" type="string"/>
                            <qField name="City" type="string"/>
                            <qField name="Age" type="integer"/>
                        </qFields>
                    </set>
                </params>
            </report>
            <report layoutID="002">
                <params>
                    <sources>
                        <source name="source1" dbURL="sampledb1.com" user="user1" password="dXNlcjE=" driver="dbDriver"/>
                    </sources>
                    <set name="Data Set" dataSource="source1" querie="select Name, Location, MaxCapacity from SchoolsTable" >
                        <qFields>
                            <qField name="Name" type="string"/>
                            <qField name="Location" type="string"/>
                            <qField name="MaxCapacity" type="integer"/>
                        </qFields>
                    </set>
                </params>
            </report>
        </reports>
    </model>      
      </xsl:param>
    
      <xsl:output indent="yes"/>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:key name="layout-ref" match="layout" use="@name" xpath-default-namespace=""/>
      <xsl:key name="report-ref" match="report" use="@layoutID" xpath-default-namespace=""/>
    
      <xsl:template match="report/text-prop[@name = 'displayName']">
          <xsl:next-match/>
          <xsl:variable name="layout" select="key('layout-ref', ., $doc2)"/>
          <xsl:variable name="report" select="key('report-ref', $layout/@ID, $doc2)"/>
          <dataSources>
              <xsl:apply-templates select="$report//source" xpath-default-namespace=""/>
          </dataSources>
          <data-sets>
              <xsl:apply-templates select="$report//set" xpath-default-namespace=""/>
          </data-sets>
    
      </xsl:template>
    
      <xsl:template match="source" xpath-default-namespace="">
          <data-source extensionID="this.is.a.fixed.value" name="{@name}">
              <xsl:apply-templates select="@* except @name"/>
          </data-source>
      </xsl:template>
    
      <xsl:template match="source/@dbURL" xpath-default-namespace="">
          <prop name="databaseURL">{.}</prop>
      </xsl:template>
    
      <xsl:template match="source/@user" xpath-default-namespace="">
          <prop name="dbUser">{.}</prop>
      </xsl:template>  
    
      <xsl:template match="source/@driver" xpath-default-namespace="">
          <prop name="DriverClass">{.}</prop>
      </xsl:template>
    
      <xsl:template match="source/@password" xpath-default-namespace="">
          <encrypted-prop name="dbPassword" encryptionID="base64">{.}</encrypted-prop>
      </xsl:template>
    
      <xsl:template match="set" xpath-default-namespace="">
          <data-set extensionID="this.is.a.fixed.value" name="{@name}">
              <xsl:apply-templates select="@*, *"/>
          </data-set>
      </xsl:template>
    
    </xsl:stylesheet>
    

    在线示例https://xsltfiddle.liberty-development.net/bFDb2Ck

    【讨论】:

    • 非常感谢您的示例和解释,这对我很有帮助!我想要做的是将来自该模板的所有数据源放入结果文档中,就像您所做的那样,然后对于数据集,因为我只会为每个报告/模板设置一个,我总是想放那个结果文档中的数据集。再次感谢您!
    • 嗨,马丁!如果我想在第一个 元素下面再添加两个 元素,我怎样才能让它们完全按照它们在第一个输入文档中的样子出现?当我将这些元素添加到其中时,它们会出现在 元素下方和 元素之前。这是更新的小提琴:xsltfiddle.liberty-development.net/bFDb2Ck/1 谢谢!
    • 很抱歉再次打扰您 Martin,我现在正在尝试对 元素执行与 相同的操作。我正在尝试添加一个新的 元素,它是 元素的子元素。我像你对 元素所做的那样,但我不知道为什么它没有改变输出(新的 元素没有被添加到它) 。我更新了 FIDDLE:xsltfiddle.liberty-development.net/bFDb2Ck/2 谢谢!
    • 如果您想使用 StackOverflow 寻求特定问题的帮助,请将它们作为单独的问题提出,样本减少到最低限度,以展示您有什么输入、您想要什么结果、您尝试过哪些代码以及你得到什么结果。不要指望人们通过交换 cmet 来解决一个大问题的各种复杂步骤。
    • 你说得对,我实际上是在创建一个新问题,但与此同时我想通了,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-21
    相关资源
    最近更新 更多