开发者

how to put templates/inheritance in config files?

I'm working on a model with a variety of categories of objects, each with a variety of versions. I'd like to have these available as defaults in the config file, but also allow users to easily customize the defaults.

This is what the general case would look like:

<containers>
  <container1>
    <object1>
      <param1>42</param1>
      <param2>3.14159</param2>
    </object1>
    <object2>
      <param3>2.71828</param3>
      <param4>auto</param4>
    </object2>
  </container1>
</containers>

I would like to process this next block and have the resulting object structure be identical to that created by the previous block.

<templates>
  <object1 id="object1_1.0">
    <param1>42</param1>
    <param2>1</param2>
  </object1>
  <object2 id=开发者_如何转开发"object2_1.0">
    <param3>2</param3>
    <param4>auto</param4>
  </object2>
</templates>
<containers>
  <container1>
    <object1 ref="object1_1.0">
      <!--param1 "inherited" as "42"-->
      <param2>3.14159</param2>
    </object1>
    <object2 ref="object2_1.0">
      <param3>2.71828</param3>
      <!--param4 "inherited" as "auto"-->
    </object2>
  </container1>
</containers>

That is, I would like to be able to get the same tree from reading in these two different input files. I expect to read in the XML and then process the resulting tree before being able to generate an object tree.

I've been unable to find any references to this being done in other projects--I'm not even sure how to search for it. If you've done this, how did you approach it? Otherwise, how do you think you would? Or have you tried this and found it more complicated than it's worth?


You can use an xslt like:

<?xml version="1.0" encoding="UTF-8"?>

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

<!-- Process all containers -->
<xsl:template match="containers">
    <xsl:for-each select="child::node()">
        <!--Copy Container node  -->
        <xsl:copy>
            <xsl:for-each select="child::node()">
                <xsl:copy>
                    <!-- first copy template node -->
                    <xsl:for-each select="//node()[@id=current()/attribute::ref]/child::node()">
                        <xsl:copy>
                            <xsl:apply-templates select="@*|node()"/>
                        </xsl:copy>
                    </xsl:for-each>
                    <!--Then the object nodes -->
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:for-each>
        </xsl:copy>
    </xsl:for-each>
</xsl:template>

<!-- =====================================================
 recursive copy,
 but skip templates nodes and ref attributes
-->
<xsl:template match="@ref"/>
<xsl:template match="templates"/>
<!-- Skip ref attributes -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

It is not perfect, because it doesn't remove duplicate params, but that should be doable (or use another xslt for this step).


Write XML that you can easily read and apply xpath and xslt:

  1. Use node names differentiated by attributes. <object2> becomes <object name="2"> and <param3> becomes <param name="3">. The "ref" attribute appears to capture this idea, but repeats information already in the XML. Infer it instead.
  2. After following #1, use attribute values that have meaning to your end users. Instead of <param2> perhaps <param name="pi">.

These two steps open up easy xpath querying such as /templates/object, which produces an iterable result in a programming language, and the ability to represent your data as nested dictionary/map/struct. Iterate once to setup the templates and a second time to override with object parameters.

If your users will edit XML files directly, consider one template or object per file and apply some naming convention and/or directory structure. This will make it much easier to identify files as the system grows.

A template:

<!-- templates/1.xml -->
<template container="1" id="1">
   <param name="1">42</param>
   <param name="2">1</param>
</object>

An object:

<!-- objects/1_1.xml -->
<object container="1" id="1">
   <!--param1 "inherited" as "42"-->
   <param name="2">3.1459</param>
</object>

Finally, content management systems often to address similar problems as the one you describe. A good place to investigate is the Java Content Repository implementation Apache Jackrabbit's Node Type Notation.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜