npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

grunt-xmlpoke

v1.0.2

Published

Updates values in XML files based on XPath queries

Downloads

4,766

Readme

grunt-xmlpoke

Updates values in XML files based on XPath queries. Similar to the xmlpoke task in NAnt.

npm version Build Status

Getting Started

This plugin requires Grunt >=0.4.2

If you haven't used Grunt before, be sure to check out the Getting Started guide, as it explains how to create a Gruntfile as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

npm install grunt-xmlpoke --save-dev

Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:

grunt.loadNpmTasks("grunt-xmlpoke");

The "xmlpoke" task

Overview

In your project's Gruntfile, add a section named xmlpoke to the data object passed into grunt.initConfig().

grunt.initConfig({
  xmlpoke: {
    updateTitle: {
      options: {
        xpath: "//title",
        value: "The Good Parts",
      },
      files: {
        "dest.xml": "src.xml",
      },
    },
  },
});

Options

options.xpath

Type: String Default value: ''

An xpath query to select one or more nodes in the source document.

options.value

Type: String or Function Default value: ''

A string value to which the value of any matched node is set.

You can also supply a function that returns the replacement value. The first argument supplied to the function will be the node on which the replacement is being made.

options.namespaces

Type: object Default value: {}

An object mapping between XML namespace prefixes and names (URIs). For example, { 'em': 'http://example.org/XML/em' }

options.valueType

Type: String Default value: 'text'

The text content of the node(s) will be set using options.value.

Setting to 'element' will replace the value of the node(s) with raw xml element(s) as defined in options.value. Setting to 'append' will append the raw xml element(s) as defined in options.value to the end of the selected node(s). Setting to 'remove' will remove the node(s) from the xml (options.value is ignored).

options.replacements

Type: Array Default value: undefined

An array of replacement options (i.e. objects with xpath and value properties)

Usage Examples

Basic Usage

In this example, the text content of an element is set to a static value. So if the testing.xml file has the content <abc></abd>, the generated result would be <abc>123</abc>.

grunt.initConfig({
  setTheNumber: {
    xmlpoke: {
      options: {
        xpath: "/abc",
        value: "123",
      },
      files: {
        "dest/basic_usage.xml": "src/testing.xml",
      },
    },
  },
});

Attribute Example

In this example, the value of an attribute is cleared. So if the testing.xml file has the content <x y="999" />, the generated result in this case would be <x y="" />.

grunt.initConfig({
  xmlpoke: {
    updateAnAttribute: {
      options: {
        xpath: "/x/@y",
        value: "",
      },
      files: {
        "dest/attribute_example.xml": "src/testing.xml",
      },
    },
  },
});

Element Example

In this example, an element is set as the child of an other element. So if the testing.xml file has the content <x><y /></x>, the generated result in this case would be <x><z /></x>.

grunt.initConfig({
  xmlpoke: {
    updateAnAttribute: {
      options: {
        xpath: "/x",
        value: "<z />",
        valueType: "element",
      },
      files: {
        "dest/element_example.xml": "src/testing.xml",
      },
    },
  },
});

Append Example

In this example, an element is added to another element. So if the testing.xml file has the content <x><y /></x>, the generated result in this case would be <x><y /><z /></x>.

grunt.initConfig({
  xmlpoke: {
    updateAnAttribute: {
      options: {
        xpath: "/x",
        value: "<z />",
        valueType: "append",
      },
      files: {
        "dest/append_example.xml": "src/testing.xml",
      },
    },
  },
});

Function Example

In this example, the value of an attribute is modified. So if the testing.xml file has the content <x y="abc" />, the generated result in this case would be <x y="ABC" />.

grunt.initConfig({
  xmlpoke: {
    upperCaseTheY: {
      options: {
        xpath: "/x/@y",
        value: function (node) {
          return node.value.toUpperCase();
        },
      },
      files: {
        "dest/function_example.xml": "src/testing.xml",
      },
    },
  },
});

Multiple XPath Queries

In this example, the same value is put intp multiple locations. So if the testing.xml file has the content <x y="999" />, the generated result in this case would be <x y="111">111</x>.

grunt.initConfig({
  xmlpoke: {
    updateAllTheThings: {
      options: {
        xpath: ["/x/@y", "/x"],
        value: "111",
      },
      files: {
        "dest/multiple_xpath_queries.xml": "src/testing.xml",
      },
    },
  },
});

Multiple Replacements

In this example, multiple replacements take place at once. So if the testing.xml file has the content <x y="999" />, the generated result in this case would be <x y="111">M</x>.

grunt.initConfig({
  xmlpoke: {
    updateACoupleOfThings: {
      options: {
        replacements: [
          {
            xpath: "/x/@y",
            value: "111",
          },
          {
            xpath: "/x",
            value: "M",
          },
        ],
      },
      files: {
        "dest/multiple_replacements.xml": "src/testing.xml",
      },
    },
  },
});

XML Namespace Example

In this example, the XML file contains namespaces (i.e. xmlns attributes). For example, an Apache Cordova config.xml file might look like this:

<?xml version='1.0' encoding='utf-8'?>
<widget id="io.cordova.hellocordova" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>HelloCordova</name>
    <description>A sample Apache Cordova application that responds to the deviceready event.</description>
    <author email="[email protected]" href="http://cordova.io">Apache Cordova Team</author>
    <content src="index.html" />
    <plugin name="cordova-plugin-whitelist" spec="1" />
    <access origin="*" />
    <allow-intent href="http://*/*" />
    <allow-intent href="https://*/*" />
    <allow-intent href="tel:*" />
    <allow-intent href="sms:*" />
    <allow-intent href="mailto:*" />
    <allow-intent href="geo:*" />
    <platform name="android">
        <allow-intent href="market:*" />
    </platform>
    <platform name="ios">
        <allow-intent href="itms:*" />
        <allow-intent href="itms-apps:*" />
    </platform>
    <cdv:custom-cordova-thing>old value</cdv:custom-cordova-thing>
</widget>

The xmlns:cdv attribute defines the namespace for the cdv prefix, but the xmlns attribute without a suffix defines the default namespace for that element and its descendants. Therefore, when targeting the <widget> element, your XPath expression will need to reference that namespace. Note, however, that the namespace does not affect attributes, only elements. In the example we define the unused cdv prefix for completeness, but it's not used in the XPath expression, so it's not required to be defined. Also, while it's simplest to keep the prefixes the same, it's not required for the prefix used in your XPath expression to match the prefix defined in the document (e.g. your XML may have an xmlns:cdv attribute, and your Grunt config could reference that same namespace URL with the prefix 'c').

grunt.initConfig({
  xmlpoke: {
    widget: {
      options: {
        namespaces: {
          w: "http://www.w3.org/ns/widgets",
          cdv: "http://cordova.apache.org/ns/1.0",
        },
        replacements: [
          {
            xpath: "/w:widget/@version",
            value: "0.2.1",
          },
          {
            xpath: "/w:widget/w:author",
            value: "Someone Else",
          },
          {
            xpath: "/w:widget/w:author/@email",
            value: "[email protected]",
          },
          {
            xpath: "/w:widget/cdv:custom-cordova-thing",
            value: "new value",
          },
        ],
      },
      files: {
        "dest/config.xml": "src/config.xml",
      },
    },
  },
});

Fail On Missing XPath

By default, if the provided XPath expression doesn't match any nodes, the task will silently continue. You can override this behavior by specifying failIfMissing in the options (either at the top level of the task, or in a sub-task), or within a single replacement.

grunt.initConfig({
  xmlpoke: {
    options: {
      failIfMissing: true,
    },
    updateACoupleOfThings: {
      options: {
        replacements: [
          {
            xpath: "/x/@y",
            value: "111",
            failIfMissing: false,
          },
          {
            xpath: "/x",
            value: "M",
          },
        ],
      },
      files: {
        "dest/element_required_attribute_optional.xml": "src/testing.xml",
      },
    },
  },
});

Contributing

In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.

Release History

  • 0.1.0 — Initial release
  • 0.2.0 — Multiple replacements at once
  • 0.2.1 — Color filename when logged
  • 0.3.0 — Allow specifying replacement value as a function (Thanks @dimasty!)
  • 0.4.0 — Allow specifying namespaces (Thanks @j1mmie!)
  • 0.5.0 — Allow replacing with XML elements, not just text (Thanks @kraihn!)
  • 0.6.0 — Allow removing XML elements (Thanks @mradcliffe!)
  • 0.7.0 — Allow appending XML elements (Thanks @njtman!)
  • 0.8.0 — Add option to fail if XPath expression doesn't match any nodes (Thanks @omatrycy!)
  • 0.8.1 — Fix broken dependency (Thanks @hbogs!)
  • 0.8.2 — Update dependencies (Thanks @greenkeeperio!)
  • 0.8.3 — Update dependencies (Thanks @greenkeeperio!)
  • 0.9.0 — Support appending XML with namespaces (Thanks @sebbi08!)
  • 0.10.0 — Better error messages (Thanks @sebbi08!)
  • 1.0.0 — Bump dependencies
  • 1.0.1 — Bump dependencies
  • 1.0.2 — Bump dependencies